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"