そういうことだったんですね

いろいろ調べたり学んだりしたことを忘れないように書き連ねています

rails - クエリの基本

クエリの流れ

  • オプションからSQL文を組み立てる
  • SQLを発行し、データベースからデータを取得する
  • 取得したデータから Rubyオブジェクトを生成する
  • after_find コールバックを呼び出す

クエリを行うメソッド

Model.take(limit)

レコードに格納されている最初の値を取得する。
limit省略時は 1。

Blog.take
SELECT "blogs".* FROM "blogs" LIMIT 1
Model.first(limit)

主キーでソートした最初の値を取得する
limit省略時は 1。

Blog.first
SELECT "blogs".* FROM "blogs" ORDER BY "blogs"."id" ASC LIMIT 1
Model.last(limit)

主キーでソートした最後の値を取得する
limit省略時は 1。

Blog.last
SELECT "blogs".* FROM "blogs" ORDER BY "blogs"."id" DESC LIMIT 1
Model.find

引数に primary_key (デフォルトは id) を指定する

Blog.find 5
SELECT "blogs".* FROM "blogs" WHERE "blogs"."id" = ? LIMIT 1  [["id", 5]]

キーに配列を指定すると複数のデータを取得できる

Blog.find [5,6]
SELECT "blogs".* FROM "blogs" WHERE "blogs"."id" IN (5, 6)
Model.find_by

引数に 検索条件を属性名:値 を渡すと、合致したレコードを取得できる

Blog.find_by user_id: 3
SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = 3 LIMIT 1

引数を複数渡すと、AND条件で結んだ条件と合致したレコードを取得できる

Blog.find_by user_id: 3, title: "タイトル"
SELECT "blogs".* FROM "blogs" WHERE "blogs"."user_id" = 3 AND "blogs"."title" = 'タイトル' LIMIT 1

複雑な条件を指定する

where を使う。

条件を直接SQLで指定する

SQLのwhere句を直接渡すことができる。
SQLインジェクション防止のため、変数を渡す際はプレースホルダを使うこと。

Blog.where "user_id = ?", params[:user_id]
SELECT "blogs".* FROM "blogs" WHERE (user_id = 3)

params[:user_id] = "1 OR 1" の場合。

プレースホルダを使わないと、

Blog.where "user_id = #{params[:user_id]}"
SELECT "blogs".* FROM "blogs" WHERE (user_id = 1 OR 1)

のように、全レコードを取得可能になってしまう。
プレースホルダを使うと、

Blog.where "user_id = ?", params[:user_id]
SELECT "blogs".* FROM "blogs" WHERE (user_id = '1 OR 1')

のように、適切にクオートされるので安全。

複数の条件を使う(1)

複数条件する場合は、プレースホルダの順番に値を渡す

Blog.where "user_id = ? AND created_at >= ?", params[:user_id], params[:created_at]
SELECT "blogs".* FROM "blogs" WHERE (user_id = 3 AND created_at >= '2014-02-17 19:15:35.523440')
複数の条件を使う(2)

? のかわりに Keyを指定し、値を Key/Value 型のHash を渡してもよい。

Blog.where "user_id = :user_id AND created_at >= :created_at", { user_id: params[:user_id], created_at: params[:created_at]}
SELECT "blogs".* FROM "blogs" WHERE (user_id = 3 AND created_at >= '2014-02-17 19:15:35.523440')