モデル(model)
モデルについて
説明
モデルとはアプリケーションが扱うデータや処理を表現する仕組みのこと
モデル名とテーブル名の規約
- 英大文字から始まる
- 英数字のみ
- 単語の区切りでは、先頭文字を大文字
- 単数形の名詞
- Entry
- UserComment
- ファイルはapp/modelsディレクトリに格納
- ファイル名は、モデル名の単語区切りを「_」にし、すべて小文字にしたもの
- app/models/entry.rb
- app/models/user_comment.rb
命名規則
種類 | 説明 | 例 |
---|---|---|
モデル名 | 先頭は大文字で単数形 | User |
モデルのファイル名 | 先頭は小文字で単数形 | user.rb |
テーブル名 | 先頭は小文字で複数形 | users |
テストスクリプト名 | xxx_test.rb | user_test.rb |
モデルを生成
説明
モデルオブジェクトを生成
保存はまだされていないため、saveメソッドなどを使って保存
生成と同時に保存したい場合は、createメソッドを使用
使い方
モデル.new(属性={})
例
モデルオブジェクトを生成
User.new
属性を指定
User.new(name: "DHH")
複数属性を指定
User.new(name: 'bob', age: '18')
ブロックで指定
users.new do |user|
user.name = 'Oscar'
end
ソースコード
モデルを生成して保存
説明
モデルを生成して保存
生成のみしたい場合は、newメソッドを使用
使い方
モデル.create(属性=nil, ブロック引数)
# 失敗したら例外発生
モデル.create!(属性=nil, ブロック引数)
例
モデルを生成して保存
User.create(name: "TestUser", profile: "profile")
whereしてcreate
users = User.where(name: 'Oscar')
users.create
属性ハッシュの配列を保存
User.create([{name: "A"},{name: "B"}])
ブロック
User.create do |user|
User.name = 'tenderlove'
end
ソースコード
IDを指定してレコードを取得
説明
IDを指定してレコードを取得
指定したIDの中に存在しないIDが1つでもあると例外が発生
使い方
モデル.find(件数..)
例
IDを指定してレコードを取得
Person.find(1)
複数IDを指定
Person.find(1, 2, 6)
配列で指定
Person.find([7, 17])
ソースコード
条件を指定して最初の1件を取得
説明
条件を指定して最初の1件を取得
存在しない場合はnil
使い方
モデル.find_by(条件..)
# 失敗したら例外発生
モデル.find_by!(条件..)
例
category_idが1の最初の値を取得
Page.find_by category_id: 1
# SQL: SELECT "pages".* FROM "pages" WHERE "pages"."category_id" = 1 LIMIT 1
category_idの1が存在しない場合
Page.find_by category_id: 1
# nil
複数条件を指定
Page.find_by category_id: 1, user_if: 1
whereで書き換える
# Page.find_by category_id: 1
Page.where(category_id: 1).take
ソースコード
条件を指定してレコードが1個しかない場合だけ取得
説明
条件を指定してレコードが1個しかない場合だけ取得
使い方
モデル.find_sole_by(条件..)
例
Product.find_sole_by(["price = %?", price])
ソースコード
分割してレコードを取得して1件ずつ処理
説明
分割してレコードを取得して1件ずつ処理
デフォルトでは1000件ずつ処理
大きなデータをもつモデルなどを処理する時に使う
使い方
モデル.find_each(start: 開始(nil), finish: 終了(nil), batch_size: バッチサイズ(1000), error_on_ignore: ErrorIgnore(nil), order: 並び順=:asc, ブロック引数)
オプション
オプション | 説明 | デフォルト値 |
---|---|---|
:batch_size | 同時処理数 | 1000 |
:start | 処理開始位置 | |
:finish | 終了するときのキー | |
:error_on_ignore | 例外を発生させる | |
:order | 主キーの順序を指定 | :asc |
例
category_idが1の値をeachする
Person.find_each do |person|
person.do_awesome_stuff
end
同時処理数を10
Post.find_each(:batch_size => 10) do |post|
end
開始位置を指定
Person.find_each(start: 2000, batch_size: 2000) do |person|
end
補足
- find_in_batchesとの違いは1件ずつ処理すること
ソースコード
分割してレコードを取得して処理
説明
分割してレコードを取得して処理
デフォルトで1000件ずつ処理
使い方
モデル.in_batches(of: バッチのサイズ=1000, start: 開始する主キーの値=nil, finish: 終了する主キーの値=nil, load: リレーションをロードするか=false, error_on_ignore: エラーを発生させるか=nil, order: 主キーの順序=:asc)
オプション
オプション | 説明 | デフォルト値 |
---|---|---|
:of | バッチのサイズ | 1000 |
:load | リレーションをロードするか | false |
:start | 処理開始位置 | |
:finish | 終了するときのキー | |
:error_on_ignore | 例外を発生させる | |
:order | 主キーの順序を指定 | :asc |
例
分割してレコードを取得して処理
Person.where("age > 21").in_batches do |relation|
relation.delete_all
sleep(10) # 削除クエリの調整
end
補足
- 処理する順序は指定できない
- find_eachとの違いは配列で値を受けとること
- 順番に処理したい場合は、find_eachを使用
ソースコード
条件を指定して初めの1件を取得し1件もなければ作成
説明
条件を指定して初めの1件を取得し1件もなければ作成
使い方
モデル.find_or_create_by(条件, ブロック引数)
# 失敗したら例外発生
モデル.find_or_create_by!(条件, ブロック引数)
例
存在しないので新しく作成
User.find_or_create_by(first_name: "Taraou")
#=> <User id: 1, first_name: "Tarou", last_name: nil>
既に存在する場合は既存のレコードを取得
User.find_or_create_by(first_name: "Taraou")
#=> <User id: 1, first_name: "Taraou", last_name: nil>
ブロック指定
User.find_or_create_by(first_name: "Scarlett") do |user|
user.last_name = "Johansson"
end
#=> <User id: 2, first_name: "Scarlett", last_name: "Johansson">
補足
- find_or_create_byとの違いは、作成する時に呼ぶメソッドがnewではなくcreate
ソースコード
データベースのユニーク制約を使って作成できなければ初めの1件を取得
説明
データベースのユニーク制約を使って作成、できなければ初めの1件を取得
find_or_create_byでは作成されるまでに別プロセスによって作成されている可能性があったので、その問題を解決した処理
create_or_find_by!はエラーの時に例外が発生
使い方
create_or_find_by(属性, ブロック引数)
# 失敗したら例外発生
f.create_or_find_by(属性, ブロック引数)
例
データベースのユニーク制約を使って作成、できなければ初めの1件を取得
User.create_or_find_by(first_name: 'Penélope')
失敗したら例外発生
User.create_or_find_by!(first_name: 'Penélope')
ソースコード
条件を指定して初めの1件を取得し1件もなければ作成
説明
条件を指定して初めの1件を取得し1件もなければ作成
使い方
モデル.find_or_initialize_by(条件, ブロック引数)
# 失敗したら例外発生
モデル.find_or_initialize_by!(条件, ブロック引数)
例
存在しないので新しく作成
User.find_or_initialize_by(first_name: 'Penélope')
既に存在する場合は既存のレコードを取得
User.find_or_initialize_by(first_name: 'Penélope')
ブロック指定
User.find_or_initialize_by(first_name: 'Scarlett') do |user|
user.last_name = "O'Hara"
end
補足
- find_or_create_byとの違いは、作成する時に呼ぶメソッドがcreateではなくnew
ソースコード
有効期限付きの署名されたIDからレコードを取得
説明
有効期限付きの署名されたIDからレコードを取得
使い方
モデル.find_signed(署名されたID, purpose: nil)
# 失敗したら例外発生
モデル.find_signed!(署名されたID, purpose: nil)
例
signed_id = User.first.signed_id expires_in: 15.minutes, purpose: :password_reset
User.find_signed signed_id #=> nil, since the purpose does not match
travel 16.minutes
User.find_signed signed_id, purpose: :password_reset #=> nil, since the signed id has expired
travel_back
User.find_signed signed_id, purpose: :password_reset #=> User.first
ソースコード
SQLを直接指定して取得
説明
SQL文を直接書いて取得
使い方
モデル.find_by_sql(SQL文, バインド=[], preparable: プレパラート=nil, ブロック引数)
例
SQL文を直接書いて取得
Page.find_by_sql("SELECT * FROM pages LIMIT 10")
# SELECT * FROM pages LIMIT 10
変数でSQL文
query = "SELECT * FROM pages LIMIT 10"
Page.find_by_sql(query)
ソースコード
SQLを直接指定して取得
説明
SQL文を直接書いて取得
使い方
select_all(SQL文, 名前=nil, バインド=[], プレパラート=nil, async: Async=false)
例
Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'").to_hash
# [
# {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
# {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
# ]
補足
- find_by_sqlとの違いは取得したオブジェクトのインスタンス化は行わないこと
ソースコード
すべてのレコードを取得
説明
すべてのレコードを取得
使い方
モデル.all
例
Page.all
# SELECT "pages".* FROM "pages"
ソースコード
先頭のレコードを取得
説明
モデルの先頭のレコードを取得
使い方
モデル.first(件数=nil)
# 失敗したら例外発生
モデル.first!(件数=nil)
例
モデルの先頭のレコードを取得
Page.first
# SQL: SELECT "pages".* FROM "pages" LIMIT 1
複数件数を取得
Page.first(3)
# SQL: SELECT "pages".* FROM "pages" LIMIT 3
orderで並び替え後のレコードを取得
Page.order(:title).first
# SQL: SELECT * FROM pages ORDER BY pages.title ASC LIMIT 1
モデルが空の場合
Page.first
# nil
ソースコード
2番目のレコードを取得
説明
2番目のレコードを検索
使い方
モデル.second()
# 失敗したら例外発生
モデル.second!()
例
Person.second # returns the second object fetched by SELECT * FROM people
Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
Person.where(["user_name = :u", { u: user_name }]).second
ソースコード
3番目のレコードを取得
説明
3番目のレコードを検索
使い方
モデル.third()
# 失敗したら例外発生
モデル.third!()
例
Person.third # returns the third object fetched by SELECT * FROM people
Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
Person.where(["user_name = :u", { u: user_name }]).third
ソースコード
4番目のレコードを取得
説明
4番目のレコードを検索
使い方
モデル.fourth()
# 失敗したら例外発生
モデル.fourth!()
例
Person.fourth # returns the fourth object fetched by SELECT * FROM people
Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
Person.where(["user_name = :u", { u: user_name }]).fourth
ソースコード
5番目のレコードを取得
説明
5番目のレコードを検索
使い方
モデル.fifth()
# 失敗したら例外発生
モデル.fifth!()
例
Person.fifth # returns the fifth object fetched by SELECT * FROM people
Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
Person.where(["user_name = :u", { u: user_name }]).fifth
ソースコード
最後のレコードを取得
説明
モデルの最後のレコードを取得
使い方
モデル.last(件数=nil)
# 失敗したら例外発生
モデル.last!(件数=nil)
例
pagesテーブルの最後のレコードを取得
Page.last
# SQL: SELECT "pages".* FROM "pages" ORDER BY "pages"."id" DESC LIMIT 1
複数を取得
Page.last(2)
# SELECT "pages".* FROM "pages" ORDER BY "pages"."id" DESC LIMIT 2
orderで並び替え後のレコードを取得
Page.order(:title).last
# SQL: SELECT * FROM pages ORDER BY pages.title DESC LIMIT 1
モデルが空の場合
Page.last
# nil
ソースコード
最後から2番目のレコードを取得
説明
最後から2番目のレコードを取得
使い方
モデル.second_to_last()
# 失敗したら例外発生
モデル.second_to_last!()
例
Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
Person.where(["user_name = :u", { u: user_name }]).second_to_last
ソースコード
最後から3番目のレコードを取得
説明
最後から3番目のレコードを取得
使い方
モデル.third_to_last()
# 失敗したら例外発生
モデル.third_to_last!()
例
Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
Person.where(["user_name = :u", { u: user_name }]).third_to_last
ソースコード
指定した数のレコードを取得
説明
引数で指定した件数のレコードを取得
取得するレコードをIDなどで指定することはできない
使い方
モデル.take(件数=nil)
# 失敗したら例外発生
モデル.take!(件数=nil)
例
1件のレコードを取得
Person.take
# SQL: SELECT * FROM people LIMIT 1
2件のレコードを取得
Person.take(2)
# SQL: SELECT * FROM people LIMIT 2
whereの後に使用
Person.where(["name LIKE '%?'", name]).take
失敗したら例外発生
Person.take!
ソースコード
カラムを指定して取得
説明
カラムを指定して取得
使い方
モデル.select(カラム名..)
例
カラムを指定して取得
person.pets.select(:id, :name)
ブロックで指定
person.pets.select do |pet|
pet.name =~ /oo/
end
ソースコード
条件に当てはまる値を全て取得
説明
条件に当てはまるレコードを全て取得
使い方
モデル.where(条件..)
例
文字列で指定
Page.where("category_id = '1'")
# SELECT "pages".* FROM "pages" WHERE "pages"."category_id" = 1
ハッシュで指定
Page.where(category_id: 1)
# SELECT "pages".* FROM "pages" WHERE "pages"."category_id" = 1
配列で指定
Page.where(["category_id = ? and url_id = ?", 1, 1])
# SELECT "pages".* FROM "pages" WHERE (category_id = 1 and url_id = 1)
プレースホルダを使用
Page.where("category_id = :category_id", {category_id: params[:category_id]})
複数キーを指定
Page.where(category_id: [1, 2])
# SELECT * FROM pages WHERE (pages.category_id IN (1,2))
NULLのすべてのデータを取得
Page.where(title: nil)
NOT条件
Page.not.where category_id: 1
# SELECT * FROM pages WHERE (pages.category_id != 1)
AND条件
Page.where(category_id: 1).where(user_id: 1)
OR条件
Page.where(category_id: 1).or(Page.where(user_id: 1))
範囲指定
User.where(:id => 1..10)
正規表現
User.where("name like '%hoge%'")
1年
User.where(created_at: '2020-1-5'.in_time_zone.all_year)
1月
User.where(created_at: '2020-1-5'.in_time_zone.all_month)
1日
User.where(created_at: '2020-1-5'.in_time_zone.all_day)
終端なしの範囲指定
User.where(age: 20..)
# SELECT * FROM users WHERE (users.age >= 20)
補足
- 文字列で指定する場合は、SQLインジェクションの脆弱性が発生する可能性があるので、外部入力されるキーに関しては配列やプレースホルダを使用してください
ソースコード
既存のwhere条件を上書き
説明
既存のwhere条件を上書き
上書きされるのは指定したキーのみで、指定されていないwhereの条件はそのまま
使い方
モデル.rewhere(条件)
例
既存のwhere条件を上書き
Post.where(trashed: true).rewhere(trashed: false)
# WHERE `trashed` = 0
指定したキーのみ上書き
Post.where(active: true).where(trashed: true).rewhere(trashed: false)
# WHERE `active` = 1 AND `trashed` = 0
ソースコード
where句全体を反転させて取得
説明
where句全体を反転させて取得
使い方
where句.invert_where()
例
where句全体を反転させて取得
User.where(accepted: true)
# WHERE `accepted` = 1
User.where(accepted: true).invert_where
# WHERE `accepted` != 1
scopeを指定
class User
scope :active, -> { where(accepted: true, locked: false) }
end
User.active
# WHERE `accepted` = 1 AND `locked` = 0
User.active.invert_where
# WHERE NOT (`accepted` = 1 AND `locked` = 0)
ソースコード
WHERE条件のハッシュを取得
説明
WHERE条件のハッシュを取得
使い方
モデル.where_values_hash(テーブル名=klass.table_name)
例
User.where(name: 'Oscar').where_values_hash
#=> {name: "Oscar"}
ソースコード
条件式に一致しないものを取得
説明
WHEREと一緒に使用し条件式に一致しないものを取得
使い方
モデル.where.not(条件..)
例
条件式に一致しないものを取得
User.where.not(name: "Jon")
# SELECT * FROM users WHERE name != 'Jon'
nilを指定
User.where.not(name: nil)
# SELECT * FROM users WHERE name IS NOT NULL
配列を指定
User.where.not(name: %w(Ko1 Nobu))
# SELECT * FROM users WHERE name NOT IN ('Ko1', 'Nobu')
複数条件
User.where.not(name: "Jon", role: "admin")
# SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
ソースコード
2つのリレーションをANDで繋ぐ
説明
2つのリレーションをANDで繋ぐ
使い方
モデルのリレーション.and(他のモデルのリレーション)
例
Post.where(id: [1, 2]).and(Post.where(id: [2, 3]))
# SELECT `posts`.* FROM `posts` WHERE `posts`.`id` IN (1, 2) AND `posts`.`id` IN (2, 3)
ソースコード
OR条件式
説明
OR条件式
使い方
モデル.or(条件式)
例
A or B
Post.where("id = 1").or(Post.where("author_id = 3"))
# SELECT `posts`.* FROM `posts` WHERE ((id = 1) OR (author_id = 3))
A, B or C
Post.where(id: 1, name: "名前").or(Post.where(age: nil))
# SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 1 AND "posts"."name" = "名前" OR "posts"."age" IS NULL)
A or B, C
Post.where(id: 1).or(Post.where(name: "名前", age: nil))
# SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 1 OR "posts"."name" = "名前" AND "posts"."age" IS NULL)
ソースコード
取得した値を並び替え
説明
取得したレコードを特定のキーで並び替える
使い方
モデル.order(引数..)
並び順
並び順 | 説明 |
---|---|
ASC | 小さい方から大きい方に並ぶ(昇順) |
DESC | 大きい方から小さい方に並ぶ(降順) |
例
pagesテーブルをcategory_idで並び替える
Page.order(:category_id)
# SELECT "pages".* FROM "pages" ORDER BY category_id
昇順で並び替える
Page.order(:category_id :asc)
# SELECT "pages".* FROM "pages" ORDER BY category_id ASC
文字列で指定
Page.order("category_id ASC")
# SELECT "pages".* FROM "pages" ORDER BY category_id ASC
複数指定
User.order(:name, email: :desc)
# SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
ソースコード
既存の並び順を指定した条件に置き換える
説明
既存の並び順を指定した条件に置き換える
使い方
モデル.reorder(ソート式..)
並び順
並び順 | 説明 |
---|---|
ASC | 小さい方から大きい方に並ぶ(昇順) |
DESC | 大きい方から小さい方に並ぶ(降順) |
例
既存の並び順を指定した条件に置き換える
User.order('email DESC').reorder('id ASC')
reorderより後の並び順は追加
User.order('email DESC').reorder('id ASC').order('name ASC')
ソースコード
取得した値を逆順に並び替え
説明
取得した値を特定のキーで逆順に並び替える
使い方
モデル.reverse_order()
例
Page.order("category_id").reverse_order
ソースコード
重複のない値を取得
説明
重複のない値を取得
使い方
モデル.distinct(重複を削除するか=true)
例
重複のない値を取得
User.select(:name).distinct
重複も削除
User.select(:name).distinct(false)
ソースコード
レコードが1個しかない場合だけ取得
説明
レコードが1個しかない場合だけ取得
使い方
モデル.sole()
例
sole()
ソースコード
空のモデルを取得
説明
空のモデルオブジェクトを取得
使い方
モデル.none()
例
空のモデルオブジェクトを取得
Post.none
ソースコード
取得するレコード数の上限を指定
説明
取得するレコード数の上限を指定
使い方
モデル.limit(最大取得行数)
例
usersテーブルから最大5件を取得
User.limit(5)
# SELECT * FROM users LIMIT 5
重複する場合あとが優先(最大20件取得)
User.limit(5).limit(20)
# SELECT * FROM users LIMIT 20
途中から指定した件数を取得
User.limit(5).offset(30)
# SELECT * FROM users LIMIT 5 OFFSET 30
ソースコード
特定のレコード位置から取得
説明
特定のレコード位置から取得
使い方
モデル.offset(取得開始位置)
例
usersテーブルの5件目以降を取得
Page.offset(5)
# SELECT "pages".* FROM "pages" LIMIT -1 OFFSET 5
途中から指定した件数を取得
User.limit(5).offset(30)
# SELECT * FROM users LIMIT 5 OFFSET 30
ソースコード
読み込み専用で取得
説明
読み込み専用としてモデルを取得
使い方
モデル.readonly(値=true)
# 失敗したら例外発生
モデル.readonly!(値=true)
例
users = User.readonly
users.first.save
# ActiveRecord::ReadOnlyRecord: ActiveRecord::ReadOnlyRecord
ソースコード
複数のテーブルを結合して取得
説明
複数のテーブルを結合して取得
使い方
モデル.joins(条件..)
例
categoryテーブルにpostテーブルを結合して取得
Category.joins(:posts)
# SELECT categories.* FROM categories INNER JOIN posts ON posts.category_id = categories.id
2個のテーブルをjoin
Post.joins(:category, :comments)
# SELECT posts.* FROM posts INNER JOIN categories ON posts.category_id = categories.id INNER JOIN comments ON comments.post_id = posts.id
ネストして結合
Page.joins(categories: :element)
# SELECT "pages".* FROM "pages" INNER JOIN "pages_categories" ON "pages_categories"."page_id" = "pages"."id" INNER JOIN "categories" ON "categories"."id" = "pages_categories"."category_id" INNER JOIN "elements" ON "elements"."id" = "categories"."element_id"
SQLで記述
User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
# SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
ソースコード
関連するモデルの左外部結合
説明
関連するモデルの左外部結合
使い方
モデル.left_outer_joins(モデル名..)
例
User.left_outer_joins(:posts)
# SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
ソースコード
関連するテーブルをまとめて取得
説明
関連するテーブルをまとめて取得
使い方
モデル.includes(引数..)
例
関連するテーブルをまとめて取得
Page.includes(:category)
# SELECT "pages".* FROM "pages"
# SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1)
複数指定
User.includes(:address, :friends)
孫モデルをまとめる
User.includes(friends: :address)
子モデルが存在するレコードを取得
User.joins(:friends).where("friends.id IS NOT NULL")
孫モデルが存在するレコードを取得
User.friends.joins(:followers).where("followers.id IS NOT NULL")
OR演算子を指定
User.where(address: 'hoge').or(User.where(friends: 'fuga'))
ソースコード
引数のプリロード
説明
引数のプリロードを可能にする
使い方
モデル.preload(引数..)
例
User.preload(:posts)
# SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
ソースコード
左外部結合を使ってすべてのレコードを取得
説明
左外部結合を使ってすべてのレコードを取得
使い方
モデル.eager_load(属性..)
例
User.eager_load(:posts)
# SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, ...
# FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
# "users"."id"
ソースコード
取得した値をグループ化
説明
取得した値をグループ化
使い方
モデル.group(グループ化キー..)
例
usersテーブルをnameでグルーピング
User.group("name")
# SELECT * FROM users GROUP BY name
複数指定
User.group('name, age')
# SELECT * FROM users GROUP BY name, age
年齢ごとの件数
User.group(:age).count
結合してグルーピング
User.joins(:categories).group("categories.name")
3つのテーブル
User.joins(categories: :tags).group("user.name")
ソースコード
取得した値を絞り込む
説明
モデルから取得した値を元に絞り込む
使い方
モデル.having(条件式)
例
絞り込む
User.having(['AVG(age) >= ?', 30])
# SELECT * FROM users HAVING AVG(age) >= 30
グループ後に絞り込む
User.select('age, count(*) as count').group('age').having('count >= ?', 30)
ソースコード
適応した条件式を除外
説明
モデルに適応した条件式を除外
使い方
モデル.except(条件式..)
例
Page.order("category DESC").except(:order)
ソースコード
レコードが参照されるテーブルを指定
説明
レコードが参照されるテーブルを指定
使い方
モデル.from(値, サブクエリ=nil)
例
レコードが参照されるテーブルを指定
Topic.select('title').from('posts')
# SELECT title FROM posts
関連付けモデル
Topic.select('title').from(Topic.approved)
# SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
サブクエリ
Topic.select('a.title').from(Topic.approved, :a)
# SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
ソースコード
SELECT文で使用するヒントを指定
説明
SELECT文で使用するヒントを指定
使い方
モデル.optimizer_hints(引数..)
例
MySQL
Topic.optimizer_hints("MAX_EXECUTION_TIME(50000)", "NO_INDEX_MERGE(topics)")
# SELECT /*+ MAX_EXECUTION_TIME(50000) NO_INDEX_MERGE(topics) */ `topics`.* FROM `topics`
PostgreSQL
Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
# SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
ソースコード
事前に設定したセレクト文を変更
説明
事前に設定したセレクト文を変更
使い方
モデル.reselect(引数..)
例
Post.select(:title, :body)
# SELECT `posts`.`title`, `posts`.`body` FROM `posts`
Post.select(:title, :body).reselect(:created_at)
# SELECT `posts`.`created_at` FROM `posts`
ソースコード
返されたリレーションをstrict_loadingモードに設定
説明
返されたリレーションをstrict_loadingモードに設定
使い方
モデル.strict_loading(値=true)
# 失敗したら例外発生
モデル.strict_loading!(値=true)
例
user = User.strict_loading.first
user.comments.to_a
=> ActiveRecord::StrictLoadingViolationError
ソースコード
他の条件とマージ
説明
他の条件とマージ
使い方
モデル.merge(他の条件, *rest)
例
Post.where(published: true).joins(:comments).merge( Comment.where(spam: false) )
# Performs a single join query with both where conditions.
recent_posts = Post.order('created_at DESC').first(5)
Post.where(published: true).merge(recent_posts)
# Returns the intersection of all published posts with the 5 most recently created posts.
# (This is just an example. You'd probably want to do this with a single query!)
ソースコード
モデルのコレクションのレコード数を取得
説明
モデルのレコード数を取得
使い方
モデルのコレクション.count(カラム名=nil)
例
テーブルの行数を計算
User.count
カラム指定
Person.count(:age)
groupで集計してから件数取得
Person.group(:city).count
ソースコード
SQL文を使って件数を取得
説明
SQL文を使って件数を取得
使い方
モデル.count_by_sql(SQL文)
例
Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
# 12
ソースコード
主キーを全て取得
説明
主キーを全て取得
使い方
モデル.ids()
例
主キーを全て取得
Person.ids
# SELECT people.id FROM people
JOIN
Person.joins(:companies).ids
# SELECT people.id FROM people INNER JOIN companies ON companies.person_id = people.id
ソースコード
カラム情報の取得
説明
指定したカラム名のオブジェクトを取得
使い方
モデル.column_for_attribute([カラム名])
例
@page = Page.find(1)
@page.column_for_attribute(:title)
ソースコード
すべての属性名を配列で取得
説明
すべての属性名を配列で取得
使い方
モデル.attribute_names()
例
Person.attribute_names
# ["id", "created_at", "updated_at", "name", "age"]
ソースコード
属性の値に似た文字列を取得
説明
属性の値に似た文字列を取得
50文字以降は省略
日時などは:db形式で返却
使い方
モデル.attribute_for_inspect(属性名)
例
属性の値に似た文字列を取得
person.attribute_for_inspect(:name)
# "\"David Heinemeier Hansson David Heinemeier Hansson D...\""
日時を取得
person.attribute_for_inspect(:created_at)
#=> "\"2012-10-22 00:15:07\""
配列を取得
person.attribute_for_inspect(:tag_ids)
#=> "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
ソースコード
全てのモデルオブジェクトと属性を取得
説明
全てのモデルオブジェクトと属性を取得
使い方
モデル.attributes()
例
person = Person.create(name: 'Francesco', age: 22)
person.attributes
# {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
ソースコード
型に変更前のハッシュを取得
説明
型に変更前のハッシュを取得
使い方
モデル.attributes_before_type_cast()
例
task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21')
task.attributes
# {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil}
task.attributes_before_type_cast
# {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
ソースコード
指定された属性を型に変更前のハッシュを取得
説明
型に変更前のハッシュを取得
使い方
モデル.read_attribute_before_type_cast(カラム名)
例
task = Task.new(id: '1', completed_on: '2012-10-21')
task.read_attribute('id') # 1
task.read_attribute_before_type_cast('id') # '1'
task.read_attribute('completed_on') # Sun, 21 Oct 2012
task.read_attribute_before_type_cast('completed_on') # "2012-10-21"
ソースコード
属性変更を取得
説明
変更点を取得
使い方
モデル.changed()
例
person.changed # []
person.name = 'bob'
person.changed # ["name"]
ソースコード
指定したカラムのレコードの配列を取得
説明
指定したカラムのレコードの配列を取得
使い方
モデル.pluck(カラム名..)
例
指定したカラムのレコードの配列を取得
Person.pluck(:id)
# SELECT people.id FROM people
複数指定
Person.pluck(:id, :name)
# SELECT people.id, people.name FROM people
whereなどと一緒に使用
Person.where(age: 21).limit(5).pluck(:id)
# SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
ソースコード
取得済みのモデルから先頭のレコードの値を1件取得
説明
whereやorderなどで取得済みのモデルから先頭のレコードの値を1件取得
relation.limit(1).pluck().firstの省略形
使い方
pick(カラム名..)
例
User.where(id: 1).pick(:name)
ソースコード
モデルの変更前と変更後の値をハッシュで取得
説明
モデルの変更前と変更後の値をハッシュで取得
使い方
モデル.changes()
例
person.changes # {}
person.name = 'bob'
person.changes # {name: ["bill", "bob"]}
ソースコード
指定されたテーブルのインデックスを配列で取得
説明
指定されたテーブルのインデックスを配列で取得
使い方
indexes(テーブル名)
例
indexes(:pages)
ソースコード
このクエリを識別できるたキャッシュキーを取得
説明
このクエリを識別できるたキャッシュキーを取得
使い方
モデル.cache_key(タイムスタンプカラム='updated_at')
例
キャッシュキーを取得
Product.where("name like ?", "%Cosmic Encounter%").cache_key
タイムスタンプカラムを指定
Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
ソースコード
モデルが保存される前に変更された値をハッシュで取得
説明
保存される前に変更された値をハッシュで取得
使い方
モデル.previous_changes()
例
person.name # "bob"
person.name = 'robert'
person.save
person.previous_changes # {name: ["bob", "robert"]}
ソースコード
モデルから読み込まれたすべてのデータベース・フィールドの名前を取得
説明
モデルから読み込まれたすべてのデータベース・フィールドの名前を取得
開発するときにどのフィールドを選択する必要があるかを判断するのに役立つ
使い方
モデル.accessed_fields()
例
class PostsController < ActionController::Base
after_action :print_accessed_fields, only: :index
def index
@posts = Post.all
end
private
def print_accessed_fields
p @posts.first.accessed_fields
end
end
ソースコード
モデルを再取得
説明
レコードを再取得
使い方
モデル.reload(オプション=nil)
例
@page = Page.find(1)
# SELECT "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1 [["id", 1]]
@page.reload
# SELECT "pages".* FROM "pages" WHERE "pages"."id" = ? LIMIT 1 [["id", 1]]
ソースコード
データベースに保存
説明
生成したモデルオブジェクトをデータベースに保存
使い方
モデル.save(オプション引数)
# 失敗したら例外発生
モデル.save!(オプション引数)
例
生成したモデルオブジェクトをデータベースに保存
user = User.new
user.name = "A"
user.save
新しいローカル変数を作らずに保存
User.new do |i|
i.name = "A"
i.save
end
属性ハッシュの保存
user = User.new(name: "A")
user.save
データベースへの保存の有無で処理を分ける
if @user.save
redirect_to :list
else
render action: "new"
end
複数の項目を保存
begin
Entry.transaction do
@many_entries.each { |entry| entry.save! }
end
vredirect_to :list
rescue ActionRecord::RecordInvalid, ActionRecord::RecordNotSaved: ex
render action: "input_multi_entries"
end
属性を変更して保存
@entry = Entry.find(params[:id])
@entry.message = "new Message"
@entry.save
複数の項目を1度に更新
@user = User.find(parms[:id])
@user.attributes = { username: 'Phusion', is_admin: true }
@user.save
ソースコード
データベースを更新
説明
条件に一致するレコードを更新
使い方
モデル.update(ID=:all, 属性)
# 失敗したら例外発生
モデル.update!(ID=:all, 属性)
例
条件に一致する属性を更新
Person.update(15, user_name: "Samuel", group: "expert")
ハッシュを使って更新
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
Person.update(people.keys, people.values)
更新メソッドの種類
メソッド | バリデーションの有無 |
---|---|
update | ○ |
update_all | × |
update_attributes | ○ |
update_attribute | × |
ソースコード
条件に一致するレコードをすべて更新
説明
条件に一致するレコードをSQLを直接実行して全て更新
updated_atとupdated_onは更新されない
使い方
モデル.update_all(SQL文のSET部分、配列、またはハッシュ)
オプション
オプション | 説明 |
---|---|
:limit | 取得する件数 |
:order | 並び順 |
例
与えられた属性を持つすべてのデータを更新
Customer.update_all wants_email: true
条件を絞り込んで更新
Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
更新するデータ数を固定
Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
全てのデータを更新して指定したカラムに値を設定
Invoice.update_all('number = id')
更新メソッドの種類
メソッド | バリデーションによるバリデーションの有無 |
---|---|
update | ○ |
update_all | × |
update_attribute | × |
ソースコード
属性ハッシュを指定して更新
説明
条件に一致するモデルオブジェクトを更新
バリデーションはスキップ
使い方
モデル.update_attribute(属性名, 値)
例
条件に一致するレコードを更新
@user.update_attribute(:name, "hoge")
更新メソッドの種類
メソッド | バリデーションによるバリデーションの有無 |
---|---|
update | ○ |
update_all | × |
update_attribute | × |
ソースコード
update_atを更新
説明
update_atを現在の時刻でアップデート
バリデーションやコールバックを実施されない
使い方
モデル.touch([名前])
例
update_atを現在の時刻でアップデート
product.touch
update_atを指定した時刻でアップデート
product.touch(time: Time.new(2015, 2, 16, 0, 0, 0))
# updates updated_at/on with specified time
ソースコード
updated_atとupdated_on属性を現在の時刻または指定された時刻に更新
説明
updated_atとupdated_on属性を現在の時刻または指定された時刻に設定
使い方
モデル.touch_all(時刻のカラム名.., time: 時間=nil)
例
現在時刻に設定
Person.all.touch_all
# "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670'"
時刻のカラム名を指定
Person.all.touch_all(:created_at)
# "UPDATE \"people\" SET \"updated_at\" = '2018-01-04 22:55:23.132670', \"created_at\" = '2018-01-04 22:55:23.132670'"
時間を指定
Person.all.touch_all(time: Time.new(2020, 5, 16, 0, 0, 0))
# "UPDATE \"people\" SET \"updated_at\" = '2020-05-16 00:00:00'"
ソースコード
現在のリレーションのレコードのカウンタを更新
説明
現在のリレーションのレコードのカウンタを更新
使い方
モデル.update_counters(ID, 条件)
例
Post.where(author_id: author.id).update_counters(comment_count: 1)
ソースコード
SQL文を発行してデータベースの属性を直接更新
説明
SQL文を発行してデータベースの属性を直接更新
使い方
モデル.update_columns(属性)
例
user.update_columns(last_request_at: Time.current)
ソースコード
複数レコードを一括登録
説明
複数レコードを一括登録
直接SQLを実行するのでバリデーションやコールバックはスキップ
使い方
モデル.insert_all(属性, returning: nil, unique_by: nil, record_timestamps: nil)
# 失敗したら例外発生
モデル.insert_all!(属性, returning: nil, unique_by: nil, record_timestamps: nil)
オプション
オプション | 説明 |
:returning | 戻り値の属性を指定(PostgreSQLのみ) |
:unique_by | 重複でスキップするカラムを指定(PostgreSQLとSQLiteのみ) |
:record_timestamps | タイムスタンプの自動設定を強制 |
例
Book.insert_all([
{ id: 1, title: "Rework", author: "David" },
{ id: 1, title: "Eloquent Ruby", author: "Russ" }
])
ソースコード
指定した条件に一致するレコードをSQLを直接実行して削除
説明
指定した条件に一致するレコードをSQLを直接実行して削除
関連付けられたモデルは削除しない
使い方
モデル.delete(IDかIDの配列)
例
指定した条件に一致するレコードをSQLを直接実行して削除
Todo.delete(1)
配列で指定
Todo.delete([2,3,4])
ソースコード
指定した条件に一致するレコードをSQLを直接実行して全て削除
説明
指定した条件に一致するレコードをSQLを直接実行して全て削除
関連付けられたモデルは削除しない
使い方
モデル.delete_all()
例
Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
ソースコード
指定された条件に一致するすべてのレコードを検索して削除
説明
指定された条件に一致するすべてのレコードを検索して削除
使い方
モデル.delete_by(条件..)
例
Person.delete_by(id: 13)
Person.delete_by(name: 'Spartacus', rating: 4)
Person.delete_by("published_at < ?", 2.weeks.ago)
ソースコード
指定した条件のレコードを削除
説明
指定した条件のレコードを削除
dependentが設定されている場合は関連付けられたモデルも削除
使い方
モデル.destroy(ID)
例
指定した条件のレコードを削除
Todo.destroy(1)
複数指定
Todo.destroy([1,2,3])
ソースコード
指定した条件のレコードと関連しているレコードをすべて削除
説明
指定した条件のレコードと関連しているレコードをすべて削除
dependentが設定されている場合は関連付けられたモデルも削除
使い方
モデル.destroy_all()
例
Person.where(age: 0..18).destroy_all
ソースコード
指定された条件に一致するレコードと関連するレコードを検索してすべて削除
説明
指定された条件に一致するレコードと関連するレコードを検索してすべて削除
使い方
モデル.destroy_by(条件..)
例
Person.destroy_by(id: 13)
Person.destroy_by(name: 'Spartacus', rating: 4)
Person.destroy_by("published_at < ?", 2.weeks.ago)
ソースコード
コピーを生成
説明
モデルのコピーを生成
使い方
モデル.clone()
例
user = User.first
new_user = user.clone
user.name # "Bob"
new_user.name = "Joe"
user.name # "Joe"
ソースコード
特定のレコードをインクリメント
説明
特定のレコードをインクリメント
使い方
モデル.increment(レコード, インクリメントする値, touch: タイムスタンプ列=nil)
# 失敗したら例外発生
モデル.increment!(レコード, インクリメントする値, touch: タイムスタンプ列=nil)
例
Page.increment(:num, 3)
ソースコード
保存されていない変更が加えられた属性の元の値を示すハッシュ
説明
保存されていない変更が加えられた属性の元の値を示すハッシュ
使い方
モデル.changed_attributes()
例
person.name #=> "bob"
person.name = 'robert'
person.changed_attributes #=> {"name" => "bob"}
ソースコード
指定した属性が存在するかチェック
説明
指定した属性が存在するかチェック
使い方
モデル.attribute_present?(属性名)
例
person.attribute_present?(:title)
# true
ソースコード
モデルが指定したメソッドを呼び出せるかチェック
説明
モデルが指定したメソッドを呼び出せるかチェック
使い方
モデル.respond_to?(メソッド名, include_private=false)
例
Personモデルがname属性を呼び出せるかチェック
person.respond_to?(:name)
# true
プライベートメソッドを呼び出せるかチェック
person.respond_to?(:private_name, true)
# true
ソースコード
モデルに指定した属性が存在するかチェック
説明
モデルに指定した属性が存在するかチェック
使い方
モデル.has_attribute?(属性)
例
指定した属性が存在する場合
person.has_attribute?(:name)
# true
指定した属性が存在しない場合
person.has_attribute?(:nothing)
# false
ソースコード
与えられた関係がこの関係と構造的に互換性があるかどうかをチェック
説明
与えられた関係がこの関係と構造的に互換性があるかどうかをチェックし、エラーを出さずにandやorのメソッドを使用できるかどうかを判断
使い方
モデル.structurally_compatible?(調べる条件)
例
Post.where("id = 1").structurally_compatible?(Post.where("author_id = 3"))
#=> true
Post.joins(:comments).structurally_compatible?(Post.where("id = 1"))
#=> false
ソースコード
保存していないレコードがあるかチェック
説明
保存していないレコードがあるかチェック
使い方
モデル.changed?()
例
@user.changed?
ソースコード
指定したモデルオブジェクトの属性が存在するかチェック
説明
指定したモデルの属性が存在するかチェック
使い方
モデル.attribute_method?(属性)
例
true
User.attribute_method?(:name)
# true
false
User.attribute_method?(:age)
# false
ソースコード
レコードの存在をチェック
説明
指定したレコードが存在するか
使い方
モデル.exists?([条件])
例
Pagesテーブルに1件でもデータは存在するか確認
Page.exists?
# SELECT 1 FROM "pages" LIMIT 1
categoryがrailsであるデータが存在するか確認
Page.exists?(category: "rails")
# SELECT 1 FROM "pages" WHERE "pages"."category" = "rails" LIMIT 1
ソースコード
新しいレコードかチェック
説明
新しいレコードかチェック
使い方
モデル.new_record?()
例
User.new_record?
ソースコード
保存済みかチェック
説明
保存済みかチェック
使い方
モデル.persisted?()
例
User.persisted?
ソースコード
削除済みかチェック
説明
削除済みかチェック
使い方
モデル.destroyed?()
例
@user.destroyed?
ソースコード
テーブルに外部キー制約が存在するかチェック
説明
テーブルに外部キー制約が存在するか
使い方
foreign_key_exists?(from_table [, to_table = nil, オプション])
例
テーブルに外部キー制約が存在するか
foreign_key_exists?(:accounts, :branches)
カラムを指定
foreign_key_exists?(:accounts, column: :owner_id)
nameを指定
foreign_key_exists?(:accounts, name: "special_fk_name")
ソースコード
例外が発生するかチェック
説明
例外が発生するかチェック
使い方
モデル.instance_method_already_implemented?(属性)
例
例外が発生する
Person.instance_method_already_implemented?(:save)
# ActiveRecord::DangerousAttributeError: save is defined by ActiveRecord
例外が発生しない
Person.instance_method_already_implemented?(:name)
# false
ソースコード
オブジェクトがモデルを実装するように設計されているかチェック
説明
オブジェクトがモデルを実装するように設計されているか
使い方
to_model()
例
class Person
include ActiveModel::Conversion
end
person = Person.new
person.to_model == person
# true
ソースコード
複数カラムをまとめる
説明
複数カラムを擬似的に1つにまとめる
使い方
モデル.composed_of(条件, オプション={})
オプション
オプション | 説明 |
---|---|
:class_name | クラス名 |
:mapping | マッピング |
:allow_nil | nilのバリデーションをスキップ |
:constructor | 条件 |
:converter | 新しい値が値オブジェクトに割り当てられたときに呼び出される |
例
複数カラムを擬似的に1つにまとめる
composed_of :temperature, mapping: %w(reading celsius)
マッピング指定
composed_of :balance, class_name: "Money", mapping: %w(balance amount), converter: Proc.new { |balance| balance.to_money }
ソースコード
URLのidの部分にid以外のものを指定
説明
URLのidの部分にid以外のものを指定
使い方
to_param()
例
class User < ActiveRecord::Base
def to_param # overridden
name
end
end
ソースコード
属性に反対のブール値を割り当てる
説明
属性に反対のブール値を割り当てる
使い方
モデル.toggle(属性)
# 失敗したら例外発生
モデル.toggle!(属性)
例
user = User.first
user.banned? #=> false
user.toggle(:banned)
user.banned? #=> true
ソースコード
関連モデルオブジェクトから新しい属性を作成
説明
関連モデルオブジェクトから新しい属性を作成
「nil」を引数で渡すと属性をリセット
使い方
モデル.create_with(属性)
例
関連オブジェクトから新しいモデルを作成
users = users.create_with(name: 'DHH')
users.new.name
# 'DHH'
属性をリセット
users = users.create_with(nil)
users.new.name
# 'Oscar'
ソースコード
生成されるクエリにSQLコメントを追加
説明
生成されるクエリにSQLコメントを追加
使い方
モデル.annotate(引数..)
例
User.annotate("selecting user names").select(:name)
# SELECT "users"."name" FROM "users" /* selecting user names */
User.annotate("selecting", "user", "names").select(:name)
# SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */
ソースコード
指定したレコードを結果のリレーションから除外
説明
指定したレコードを結果のリレーションから除外
使い方
モデル.excluding(レコード..)
例
Post.excluding(post)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
Post.excluding(post_one, post_two)
# SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
ソースコード
モデルをハッシュ形式のJSONに変換
説明
モデルをハッシュ形式のJSONに変換
使い方
モデル.as_json(オプション=nil)
オプション
オプション | 説明 | デフォルト値 |
---|---|---|
:root | ノード名を含める | false |
:only | 取得する要素を指定 | |
:except | 取得しない要素を指定 | |
:methods | メソッドの呼び出し結果を含める | |
:include | 関連付け |
例
ハッシュ形式のJSONに変換
user.as_json
# {id: 1, name: "Konata Izumi", age: 16, created_at: "2006-08-01T17:27:133.000Z", awesome: true}
ノード名を含める
user.as_json(root: true)
#=> { "user" => { "id" => 1, "age" => 16, "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true } }
取得する要素を指定
user.as_json(only: [:id, :age])
#=> { "id" => 1, "age" => 16 }
取得しない要素を指定
user.as_json(except: [:id, :created_at, :name])
#=> { "age" => 16, "awesome" => true }
メソッドを指定
user.as_json(methods: :permalink)
#=> { "id" => 1, "name" => "Konata Izumi", "age" => 16, "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true, "permalink" => "1-konata-izumi" }
関連付け
user.as_json(include: :posts)
#=> { "id" => 1, "name" => "Konata Izumi", "age" => 16, "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true, "posts" => [ { "id" => 1, "author_id" => 1, "title" => "Welcome to the weblog" }, { "id" => 2, "author_id" => 1, "title" => "So I was thinking" } ] }
ソースコード
JSON文字列からモデルの属性を設定
説明
JSON文字列からモデルの属性を設定
使い方
モデル.from_json(JSON文字列, include_root=include_root_in_json)
例
json = { name: 'bob', age: 22, awesome:true }.to_json
person = Person.new
person.from_json(json) #=> #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
person.name #=> "bob"
person.age #=> 22
person.awesome #=> true
ソースコード
全てのバリデーションをクリア
説明
全てのバリデーションをクリア
使い方
モデル.clear_validators!()
例
Person.clear_validators!
ソースコード
分割してレコードを取得して処理
説明
分割してレコードを取得して処理
デフォルトで1000件ずつ処理
使い方
モデル.in_batches([オプション]) do |i|
処理内容
end
オプション
オプション | 説明 | デフォルト値 |
---|---|---|
:of | 同時処理数 | 1000 |
:load | ロードするか | false |
:start | 処理開始位置 | |
:finish | 終了するときのキー | |
:error_on_ignore | 例外を発生させる | |
:order | 主キーの順序を指定 | :asc |
例
分割してレコードを取得して処理
Person.where("age > 21").in_batches do |relation|
relation.delete_all
sleep(10) # Throttle the delete queries
end
分割して取得して削除
Person.in_batches.delete_all
分割して取得して更新
Person.in_batches.update_all(awesome: true)
補足
- find_in_batchesとの違いはActiveRecord::Relationで値を返す
ソースコード
指定した条件以外の条件をクエリから除外
説明
指定した条件以外の条件をクエリから削除
使い方
モデル.only(条件..)
例
条件式を削除
Post.order('id asc').only(:where)
複数指定
Post.order('id asc').only(:where, :order)
ソースコード
トランザクション
説明
分割不可能な複数のレコードの更新を1つの単位にまとめて処理すること
特徴
- データベース内の情報の整合性を保つための手段
- 複数のデータベースにまたがる分散トランザクションはサポートしていない
- 使用するにはデータベースがトランザクションをサポートしていることが必要
使い方
モデル.transaction(requires_new: 新規作成=nil, isolation: isolation=nil, joinable: 結合=true, ブロック引数)
- ブロック内のすべての処理が正常に行われた場合に保存
- エラーが発生した場合は、ロードバック
例
def new
User.transaction do
a1 = User.new(name: 'tarou')
a1.save!
a2 = User.new(name: 'jirou')
a2.save!
end
render text: '更新に成功しました'
rescue: e
render text: e.message
end
ソースコード
データベースのロック
楽観的ロック
あらかじめカラムのロックバージョンを記録しておき、更新時にロックバージョンが変わっていないことをバリデーションして保存
class CreateAddLockColumnToEntries < ActiveRecord::Migration
def self.up
create_table :add_lock_column_to_entries do |t|
t.integer :entries, :lock_version, null: false, default: 0
end
end
def self.down
drop_table :add_lock_column_to_entries
end
end
悲観的ロック
データベース側でレコードをロックし、並行に更新できないようにする
locked_entry = Entry.find(1,lock: true)
- MySQLとPostgreSQLでのみ利用可能
特定の値のセットによる順序の指定
説明
特定の値のセットによる順序の指定
使い方
モデル.in_order_of(カラム, 値)
例
User.in_order_of(:id, [1, 5, 3])
# SELECT "users".* FROM "users" ORDER BY FIELD("users"."id", 1, 5, 3)
ソースコード
属性のエイリアスを作成
説明
属性のエイリアスを作成
使い方
alias_attribute(エイリアス名, エイリアス元の属性名)
例
alias_attribute :subject, :title
ソースコード
属性のハッシュを渡すことですべての属性を設定
説明
属性のハッシュを渡すことですべての属性を設定
使い方
assign_attributes(属性のハッシュ)
例
class Cat
include ActiveModel::AttributeAssignment
attr_accessor :name, :status
end
cat = Cat.new
cat.assign_attributes(name: "Gorby", status: "yawning")
cat.name #=> 'Gorby'
cat.status #=> 'yawning'
cat.assign_attributes(status: "sleeping")
cat.name #=> 'Gorby'
cat.status #=> 'sleeping'
ソースコード
すべての属性名を配列で取得
説明
すべての属性名を配列で取得
使い方
to_key()
例
class Person
include ActiveModel::Conversion
attr_accessor :id
def initialize(id)
@id = id
end
end
person = Person.new(1)
person.to_key #=> [1]
ソースコード
URLでの使用に適したオブジェクトのキーを表す文字列
説明
URLでの使用に適したオブジェクトのキーを表す文字列
使い方
to_param()
例
class Person
include ActiveModel::Conversion
attr_accessor :id
def initialize(id)
@id = id
end
def persisted?
true
end
end
person = Person.new(1)
person.to_param
#=> "1"
ソースコード
オブジェクトに関連するパスを示す文字列
説明
オブジェクトに関連するパスを示す文字列
使い方
to_partial_path()
例
class Person
include ActiveModel::Conversion
end
person = Person.new
person.to_partial_path
#=> "people/person"
ソースコード
BCryptパスワードを設定して認証するためのメソッド
説明
BCryptパスワードを設定して認証するためのメソッド
使い方
has_secure_password(属性=:password, validations: バリデーション=true)
例
class User < ActiveRecord::Base
has_secure_password
has_secure_password :recovery_password, validations: false
end
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save #=> false, password required
user.password = 'mUc3m00RsqyRe'
user.save #=> false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save #=> true
user.recovery_password = "42password"
user.recovery_password_digest #=> "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
user.save #=> true
user.authenticate('notright') #=> false
user.authenticate('mUc3m00RsqyRe') #=> user
user.authenticate_recovery_password('42password') #=> user
User.find_by(name: 'david')&.authenticate('notright') #=> false
User.find_by(name: 'david')&.authenticate('mUc3m00RsqyRe') #=> user
ソースコード
オブジェクトのシリアル化されたハッシュ
説明
オブジェクトのシリアル化されたハッシュ
使い方
serializable_hash(オプション=nil)
例
色々な使用方法
class Person
include ActiveModel::Serialization
attr_accessor :name, :age
def attributes
{'name' => nil, 'age' => nil}
end
def capitalized_name
name.capitalize
end
end
person = Person.new
person.name = 'bob'
person.age = 22
person.serializable_hash #=> {"name"=>"bob", "age"=>22}
person.serializable_hash(only: :name) #=> {"name"=>"bob"}
person.serializable_hash(except: :name) #=> {"age"=>22}
person.serializable_hash(methods: :capitalized_name)
#=> {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}
ソースコード
リレーションから名前付きのアソシエーションを抽出
説明
リレーションから名前付きのアソシエーションを抽出
使い方
extract_associated(アソシエーション)
例
account.memberships.extract_associated(:user)
#=> Returns collection of User records
ソースコード
レコードがまだ読み込まれていない場合にデータベースからレコードを読み込む
説明
レコードがまだ読み込まれていない場合にデータベースからレコードを読み込む
使い方
モデル.load([ブロック])
例
Post.where(published: true).load
#=> #<ActiveRecord::Relation>
ソースコード
バックグラウンドのスレッドプールからクエリを実行するようにスケジュール
説明
バックグラウンドのスレッドプールからクエリを実行するようにスケジュール
使い方
モデル.load_async()
例
Post.where(published: true).load_async
#=> #<ActiveRecord::Relation>
ソースコード
デフォルトのスコープを定義
説明
デフォルトのスコープを定義
使い方
default_scope(条件式=nil, all_queries: 全てのクエリ=nil, ブロック引数)
例
class Article < ActiveRecord::Base
default_scope { where(published: true) }
end
Article.all
# SELECT * FROM articles WHERE published = true
ソースコード
すでに設定されているスコープを除いたモデルのスコープを取得
説明
すでに設定されているスコープを除いたモデルのスコープを取得
使い方
unscoped(ブロック引数)
例
でに設定されているスコープを除いたモデルのスコープを取得
Post.unscoped.all
ブロック
Post.unscoped {
Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
}
ソースコード
条件式を削除
説明
条件式を削除
使い方
モデル.unscope(条件式..)
例
条件式を削除
User.order('email DESC').unscope(:order)
複数指定
User.select(:id).order('email DESC').unscope(:select, :order)
ソースコード
scopeを使ってモデルを拡張
説明
モジュールやブロックメソッドを引数に与えてモデルをscopeで拡張
返されたオブジェクトをさらに拡張することもできる
使い方
モデル.extending(モジュール.., ブロック引数)
例
モジュール
module Pagination
def page(number)
# pagination code goes here
end
end
scope = Model.all.extending(Pagination)
scope.page(params[:page])
ブロック
module Pagination
def page(number)
# pagination code goes here
end
end
scope = Model.all.extending do
def page(number)
# pagination code goes here
end
end
scope.page(params[:page])
ソースコード
すべてのクエリを現在のスコープに収める
説明
すべてのクエリを現在のスコープに収める
使い方
モデル.scoping(all_queries: 全てのクエリ=nil, ブロック引数)
例
Comment.where(post_id: 1).scoping do
Comment.first
end
#=> SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
ソースコード
取得する時のSQLを表示
説明
取得する時のSQLを表示
使い方
モデル.to_sql()
例
User.where(name: 'Oscar').to_sql
# SELECT "users".* FROM "users" WHERE "users"."name" = 'Oscar'
ソースコード
親と子のテーブルのレコードの継承関係
説明
親と子のテーブルのレコードの継承関係
使い方
delegated_type(ロール, types: 型=nil, オプション引数)
オプション
オプション | 説明 | デフォルト値 |
:foreign_key | 関連オブジェクトで使用する外部キー名 | :foreign_key |
:primary_key | 関連オブジェクトの主キー | id |
例
class Entry < ApplicationRecord
delegated_type :entryable, types: %w[ Message Comment ], dependent: :destroy
end
Entry#entryable_class #=> +Message+ or +Comment+
Entry#entryable_name #=> "message" or "comment"
Entry.messages #=> Entry.where(entryable_type: "Message")
Entry#message? #=> true when entryable_type == "Message"
Entry#message #=> returns the message record, when entryable_type == "Message", otherwise nil
Entry#message_id #=> returns entryable_id, when entryable_type == "Message", otherwise nil
Entry.comments #=> Entry.where(entryable_type: "Comment")
Entry#comment? #=> true when entryable_type == "Comment"
Entry#comment #=> returns the comment record, when entryable_type == "Comment", otherwise nil
Entry#comment_id #=> returns entryable_id, when entryable_type == "Comment", otherwise nil
ソースコード
カラムの平均値を計算
説明
カラムの平均値を計算
使い方
モデル.average(カラム名)
例
Page.average(:count)
# SELECT AVG("pages"."count") AS avg_id FROM "pages"
ソースコード
カラムの最大値を計算
説明
カラムの最大値を計算
使い方
モデル.maximum(カラム名)
例
User.maximum('age')
# SELECT MAX("users"."age") AS max_id FROM "users"
ソースコード
カラムの最小値を計算
説明
カラムの最小値を計算
使い方
モデル.minimum(カラム名)
例
User.minimum('age')
# SELECT MIN("users"."age") AS min_id FROM "users"
ソースコード
カラムの合計値を計算
説明
カラムの合計値を計算
使い方
モデル.sum(カラム名=nil, ブロック引数)
例
Rating.sum(:score)
# SELECT SUM("Ratings"."score") AS sum_id FROM "Ratings"
ソースコード
汎用的なカラム処理
説明
汎用的なカラム処理
使い方
モデル.calculate(処理方法, カラム名)
処理方法
処理方法 | 説明 |
---|---|
:count | カウント |
:sum | 合計値 |
:average | 平均値 |
:minimum | 最小値 |
:maximum | 最大値 |
例
Page.calculate(:count, :all)
# SELECT COUNT(*) FROM "pages"