Ruby on Rails
ActiveRecord照会インターフェース
サーチ…
前書き
ActiveRecordは、ビジネスデータとロジックを表すシステムのレイヤーであるMVCのMです。リレーショナルデータベース管理システム内のテーブルへのアプリケーションの豊富なオブジェクトを接続する技術がO bject R elational Mの apper(ORM)です。
ActiveRecordは、データベースのクエリを実行し、ほとんどのデータベースシステムと互換性があります。どのデータベースシステムを使用していても、ActiveRecordメソッド形式は常に同じです。
.where
where
メソッドは任意のActiveRecord
モデルで使用でき、指定された条件に一致するレコードのセットをデータベースに問い合わせることができます。
where
メソッドは、キーがモデルが表すテーブルの列名に対応するハッシュを受け入れます。
簡単な例として、次のモデルを使用します。
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
end
最初の名前のSven
すべての人を見つけるには:
people = Person.where(first_name: 'Sven')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven'"
Sven
とSchrodinger
名字を持つすべての人を見つけるには:
people = Person.where(first_name: 'Sven', last_name: 'Schrodinger')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven' AND last_name='Schrodinger'"
上記の例では、sql出力は、 first_name
とlast_name
両方が一致した場合にのみレコードが返されることを示しています。
OR条件付きクエリ
first_name == 'Bruce'
OR last_name == 'Wayne'
レコードを検索するには
User.where('first_name = ? or last_name = ?', 'Bruce', 'Wayne')
# SELECT "users".* FROM "users" WHERE (first_name = 'Bruce' or last_name = 'Wayne')
。配列あり
任意のActiveRecordモデルのwhere
メソッドを使用して、 WHERE column_name IN (a, b, c, ...)
という形式のSQLを生成できます。これは、引数として配列を渡すことによって実現されます。
簡単な例として、次のモデルを使用します。
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
end
people = Person.where(first_name: ['Mark', 'Mary'])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary')"
配列にnil
が含まれている場合、その列がnull
かどうかを確認するためにSQLが変更されnull
。
people = Person.where(first_name: ['Mark', 'Mary', nil])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary') OR first_name IS NULL"
スコープ
スコープは、 ActiveRecord
モデルで定義済みのフィルタとして機能します。
スコープはscope
クラスメソッドを使用して定義されます。
簡単な例として、次のモデルを使用します。
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
#attribute :age, :integer
# define a scope to get all people under 17
scope :minors, -> { where(age: 0..17) }
# define a scope to search a person by last name
scope :with_last_name, ->(name) { where(last_name: name) }
end
スコープはモデルクラスから直接呼び出すことができます:
minors = Person.minors
スコープは連鎖できます。
peters_children = Person.minors.with_last_name('Peters')
where
メソッドや他のクエリー型メソッドも連鎖することができます:
mary_smith = Person.with_last_name('Smith').where(first_name: 'Mary')
背後では、スコープは単純な標準クラスのメソッドの構文的な砂糖です。たとえば、これらのメソッドは機能的に同じです。
scope :with_last_name, ->(name) { where(name: name) }
# This ^ is the same as this:
def self.with_last_name(name)
where(name: name)
end
デフォルトスコープ
モデルのすべての操作のデフォルトスコープを設定します。
scope
メソッドとクラスメソッドの間には顕著な違いがありscope
。scope
定義スコープは、そのロジックがnilを返す場合でも常にActiveRecord::Relation
返します。しかし、クラスメソッドはそのようなセーフティネットを持たず、何かを返すと連鎖性を破る可能性があります。
どこにもない
where
句は使用して否定することができwhere.not
構文:
class Person < ApplicationRecord #attribute :first_name, :string end people = Person.where.not(first_name: ['Mark', 'Mary']) # => SELECT "people".* FROM "people" WHERE "people"."first_name" NOT IN ('Mark', 'Mary')
ActiveRecord 4.0以降でサポートされています。
注文
.order
を使用してActiveRecordクエリ結果を注文することができます:
User.order(:created_at)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]
指定されていない場合は、昇順に並べ替えられます。以下のようにして指定することができます:
User.order(created_at: :asc)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]
User.order(created_at: :desc)
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]
.order
は文字列も受け入れます
User.order("created_at DESC")
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]
文字列は生のSQLであるため、属性だけでなくテーブルも指定できます。自分のrole
名に従ってusers
を注文する場合は、次のusers
にします。
Class User < ActiveRecord::Base
belongs_to :role
end
Class Role < ActiveRecord::Base
has_many :users
end
User.includes(:role).order("roles.name ASC")
order
スコープは、Arelノードを受け入れることもできます。
User.includes(:role).order(User.arel_table[:name].asc)
ActiveRecord Bang(!)メソッド
失敗した場合にfalse
値ではなく例外を発生させるためにActiveRecordメソッドが必要な場合は、追加することができ!
彼らへ。これはとても重要です。あなたが使用しない場合、いくつかの例外/失敗は捕まえにくいので!それらの上に。開発サイクルでこれを実行して、ActiveRecordコードをこのように書くことで、時間と手間を省くことをお勧めします。
Class User < ActiveRecord::Base
validates :last_name, presence: true
end
User.create!(first_name: "John")
#=> ActiveRecord::RecordInvalid: Validation failed: Last name can't be blank
bang ( !
)を受け入れるActiveRecordメソッドは次のとおりです。
-
.create!
-
.take!
-
.first!
-
.last!
-
.find_by!
-
.find_or_create_by!
-
#save!
-
#update!
- すべてのARダイナミックファインダ
.find_by
find_by
を使用して、テーブル内の任意のフィールドでレコードを見つけることができます。
したがって、 first_name
属性を持つUser
モデルを使用すると、次のことができます。
User.find_by(first_name: "John")
#=> #<User id: 2005, first_name: "John", last_name: "Smith">
find_by
がデフォルトで例外をスローしないことをfind_by
てfind_by
てください。結果が空集合であれば、 find
代わりにnil
を返しfind
。
例外が必要な場合は、 find_by!
使用することができますfind_by!
それは、 find
ようなActiveRecord::RecordNotFound
エラーを発生させfind
。
。すべて削除
多くのレコードをすばやく削除する必要がある場合、 ActiveRecordは.delete_all
メソッドを提供します。モデル上で直接呼び出す、そのテーブル内のすべてのレコードを削除する、またはコレクションを削除する。ただし、 .delete_all
はオブジェクトをインスタンス化しないため、コールバックは提供されません( before_*
およびafter_destroy
はafter_destroy
ません)。
User.delete_all
#=> 39 <-- .delete_all return the number of rows deleted
User.where(name: "John").delete_all
ActiveRecordの大文字と小文字を区別しない検索
ActiveRecordモデルで類似の値を検索する必要がある場合は、 LIKE
またはILIKE
を使用するように誘惑されるかもしれませんが、データベースエンジン間では移植できません。同様に、常にダウンケーシングまたはアップケーシングに頼ることは、パフォーマンス上の問題を引き起こす可能性があります。
ActiveRecordの基礎となるArel matches
メソッドを使用すると、安全な方法でこれを行うことができます:
addresses = Address.arel_table
Address.where(addresses[:address].matches("%street%"))
Arelは、構成されたデータベースエンジンに適切なLIKEまたはILIKE構造を適用します。
最初と最後のレコードを取得する
Railsは、データベースからfirst
とlast
レコードを取得する非常に簡単な方法を持っています。
users
テーブルからfirst
レコードを取得するには、次のコマンドを入力する必要があります。
User.first
それは次のsql
クエリを生成します:
SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
そして、次の記録を返すでしょう:
#<User:0x007f8a6db09920 id: 1, first_name: foo, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >
users
テーブルからlast
レコードを取得するには、次のコマンドを入力する必要があります。
User.last
それは次のsql
クエリを生成します:
SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
そして、次の記録を返すでしょう:
#<User:0x007f8a6db09920 id: 10, first_name: bar, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >
最初と最後のメソッドに整数を渡すと、 LIMITクエリが作成され、オブジェクトの配列が返されます。
User.first(5)
これは、次のsql
クエリを生成します。
SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 5
そして
User.last(5)
これは、次のsql
クエリを生成します。
SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 5
.groupと.count
私たちはProduct
モデルを持っており、それらのcategory
グループ化したいと考えていcategory
。
Product.select(:category).group(:category)
これにより、次のようにデータベースが照会されます。
SELECT "product"."category" FROM "product" GROUP BY "product"."category"
グループ化されたフィールドも選択されていることを確認します。グループ化は、 categories
発生(この場合)を数えるのに特に便利です。
Product.select(:category).group(:category).count
クエリが示すように、すべてのレコードを最初に取得し、コード内でカウントするよりもはるかに効率的な、カウントにデータベースを使用します:
SELECT COUNT("products"."category") AS count_categories, "products"."category" AS products_category FROM "products" GROUP BY "products"."category"
.distinct(または.uniq)
結果から重複を削除する場合は、 .distinct()
使用できます。
Customers.select(:country).distinct
これは、次のようにデータベースに照会します。
SELECT DISTINCT "customers"."country" FROM "customers"
.uniq()
は同じ効果を持ちます。 Rails 5.0では廃止され、バージョン5.1のRailsから削除されます。その理由は、 unique
という単語は異なるものと同じ意味を持たず、誤解を招く可能性があるからです。さらに、 distinct
はSQL構文に近い。
結合
joins()
使用すると、テーブルを現在のモデルに結合できます。例えば、
User.joins(:posts)
次のSQLクエリを生成します。
"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id""
テーブルに参加すると、そのテーブルにアクセスできます。
User.joins(:posts).where(posts: { title: "Hello world" })
複数形に注意してください。あなたの関係が:has_many
場合、 joins()
引数は複数形にする必要があります。それ以外の場合は、単数形を使用します。
ネストされたjoins
:
User.joins(posts: :images).where(images: { caption: 'First post' })
それは次を生成する:
"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" INNER JOIN "images" ON "images"."post_id" = "images"."id""
含まれるもの
ActiveRecord with includes
は、指定されたすべてのアソシエーションが最小数のクエリを使用してロードさincludes
ようにします。したがって、関連付けられたテーブルを持つデータのテーブルをクエリすると、両方のテーブルがメモリにロードされます。
@authors = Author.includes(:books).where(books: { bestseller: true } )
# this will print results without additional db hitting
@authors.each do |author|
author.books.each do |book|
puts book.title
end
end
Author.joins(:books).where(books: { bestseller: true } )
は、 書籍を読み込まずに条件付きの著者だけをメモリに読み込みます 。ネストされた関連付けに関する追加情報が必要ない場合は、 joins
使用しjoins
。
@authors = Author.joins(:books).where(books: { bestseller: true } )
# this will print results without additional queries
@authors.each { |author| puts author.name }
# this will print results with additional db queries
@authors.each do |author|
author.books.each do |book|
puts book.title
end
end
リミットとオフセット
limit
を使用してフェッチするレコードの数を指定し、 offset
を使用してレコードの数を通知してスキップしてレコードを返すことができます。
例えば
User.limit(3) #returns first three records
これは、次のSQLクエリを生成します。
"SELECT `users`.* FROM `users` LIMIT 3"
上記のクエリではオフセットが記述されていないので、最初の3つのレコードが返されます。
User.limit(5).offset(30) #returns 5 records starting from 31th i.e from 31 to 35
これは、次のSQLクエリを生成します。
"SELECT `users`.* FROM `users` LIMIT 5 OFFSET 30"