0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails基礎】Active Recordとは?

Last updated at Posted at 2022-08-26

はじめに

ActiveRecordsについてあまり理解していないので、今回深掘りしてみました。

Active RecordとはRailsにおけるObject/Relational Mapping (ORM) です。
※訳:オブジェクト関係マッピング

Object/Relational Mapping (ORM)とは?🤔

以下Wekipediaより

オブジェクト関係マッピング(英: Object-relational mapping、O/RM、ORM)とは、データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である

つまり、RubyでDBを操作するための技法ということですね!!👏

RailsアプリでDBに変更を加えるとき、Rubyのコードで直感的にDBを操作することができるのもActive Record様のおかげ

また、ActiveRecord様のおかげでDBの種類(MySQL, PostgreSQL等)に関わらず同じコードで操作可能になります!

Active Recordはどのように機能している?

では、お馴染みのrails g modelをして、DBにテーブルを追加して行きます!

rails g model Post title:string
create	db/migrate/20220826_create_post.rb
create	app/models/post.rb

このファイルはどこから来ているのでしょうか?👀
これはrails g modelコマンドを実行時にrailsのmodel_generator.rbが呼び出されています!

コードを確認してみます!

....
# creates the migration file for the model.
      def create_migration_file
        return if skip_migration_creation?
        attributes.each { |a| a.attr_options.delete(:index) if a.reference? && !a.has_index? } if options[:indexes] == false
        migration_template "../../migration/templates/create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")
      end

      def create_model_file
        generate_abstract_class if database && !custom_parent?
        template "model.rb", File.join("app/models", class_path, "#{file_name}.rb")
      end
....

1つ目のメソッドはマイグレーションファイル、
2つ目のメソッドはモデルファイルを生成していますね!!

下記の記述をさら見てみます

migration_template "../../migration/templates/create_table_migration.rb", File.join(db_migrate_path, "create_#{table_name}.rb")

create_table_migration.rb

create_table_migration.rb
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
  def change
    create_table :<%= table_name %><%= primary_key_type %> do |t|
<% attributes.each do |attribute| -%>
<% if attribute.password_digest? -%>
      t.string :password_digest<%= attribute.inject_options %>
<% elsif attribute.token? -%>
      t.string :<%= attribute.name %><%= attribute.inject_options %>
<% elsif attribute.reference? -%>
      t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %><%= foreign_key_type %>
<% elsif !attribute.virtual? -%>
      t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
<% end -%>
<% end -%>
<% if options[:timestamps] %>
      t.timestamps
<% end -%>
    end
<% attributes.select(&:token?).each do |attribute| -%>
    add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>, unique: true
<% end -%>
<% attributes_with_index.each do |attribute| -%>
    add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
<% end -%>
  end
end

なんかみたことある形....

これは、、
rails g modelのときに生成されるマイグレーションファイルと同じフォーマットですね!!!

class CreatePost < ActiveRecord::Migration
    def change
        create_table :post do |t|
            t.integer :title
 
            t.timestamps
        end
    end
end

ということは、rails g model実行時に渡したモデル名やカラムが
ファイルを生成時に使われていることがわかりますね!

次にrailsdb:migrateを実行し、DBにテーブルを作ります

ということは、rails g model実行時に渡したモデル名やカラムが
ファイルを生成時に使われていることがわかりますね!

次にrailsdb:migrateを実行し、DBにテーブルを作ります。
では、データを入れて行きましょう!

post = Post.new title: "This is title"

Postのインスタンスを生成してみます。
次にDBに保存するために、post.saveをします。

INSERT INTO "post" ("title", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["title", "This is title"], ["created_at", Fri, 26 Aug 2022 18:20:12 UTC +00:00], ["updated_at", Fri, 26 Aug 2022 18:20:12 UTC +00:00]]

DBに保存時このメソッドを使用しています。

rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
# Executes an INSERT query and returns the new record's ID
#
# +id_value+ will be returned unless the value is +nil+, in
# which case the database will attempt to calculate the last inserted
# id and return that value.
#
# If the next id was calculated in advance (as in Oracle), it should be
# passed in as +id_value+.
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
  sql, binds = to_sql_and_binds(arel, binds)
    value = exec_insert(sql, name, binds, pk, sequence_name)
    id_value || last_inserted_id(value)
  end

まとめ

Active Recordのおかげで、直感的にDB操作することが可能になることがわかりました。

Active Recordに関わらず、Railsはあまり深い理解をせずとも動いてくれるので、
裏でどのようになっているかはしっかりと理解する必要があると感じました。
今後もどのようなロジックで動いているのかしっかり調べていこうと思いました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?