【2021年から Ruby on Rails をはじめる人向け】 Ruby on Rails 6 入門 Part 6 ~ Rails 上でデータベース検索~

【2021年から Ruby on Rails をはじめる人向け】 Ruby on Rails 6 入門 Part 6 ~ Rails 上でデータベース検索~

link です。

今回は Rails の Controller 上でデータベースを検索する方法を勉強します。

この記事は Ruby on Rails 6 入門 Part 5 の続きです。

前提条件

  • Windows 10
  • Ruby 3
  • Ruby on Rails 6

ActiveRecord でデータベース検索

Rails には SQL を使わずにデータベースを検索できる ActiveRecord という機能があります。

この機能を使って、データベースを検索する機能を作成してみましょう。

まず、app/controller/people_controller.rb に以下の find メソッドを追加します。

def find
  @msg = 'please type search word...'
  @people = Array.new
  if request.post? then
    @people.push(Person.find(params[:find]))
  end
end

次に app/views/people/find.html.erb を作成して以下のように書きます。

<h1 class="display-4 text-primary">People#Find</h1>
<p><%= @msg %></p>
<%= form_with model: @person do |form| %>
  <div class="form-group">
    <label for="find">Find</label>
    <%= form.text_field("find", {class:"form-control"}) %>
  </div>
<%= form.submit("Click", {class:"btn btn-primary"}) %>
<% end %>

<table class="table">
  <tr>
    <th>Id</th><th>Name</th><th>Age</th>
  </tr>
  <% @people.each do |obj| %>
  <tr>
    <td><%= obj.id %></td>
    <td><%= obj.name %></td>
    <td><%= obj.age %></td>
  </tr>
  <% end %>
</table>

config/route.rb にルーティングを追加します。追加するときは get 'people/:id', to: 'people#show' より上部で宣言されるようにしましょう。

get 'people/find'
post 'people/find', to: 'people#find'

localhost:3000/people/find にアクセスして、以下の画像のような画面になっていれば、下準備は完了です。

ruby on rails6 1

ActiveRecord のメソッドの一部

SQL を使ってできることは ActiveRecord でほぼ全てできます。もちろん独自の SQL 文を使用するための find_by_sql メソッドも存在します。

今回はデータを取得するメソッドの一部を紹介します。ここで紹介したメソッド以外にも一番最初に取得したレコードを返す first や 多数のレコードに対して反復処理を行う find_each が存在します。

find

主キーと一致するレコードを取得します。

app/controller/people_controller.rb に追加した find メソッド内の Person.find(params[:find]) が ActiveRecord の find メソッドです。

例えば、主キーが id だとすると、 2 で検索すれば、

ruby on rails6 2

id が 2 のレコードのみを返します。

ruby on rails6 3

find_by

find_by は与えられた条件にマッチするレコード群のうち、最初のレコードのみを返します。

まず、 app/controller/people_controller.rbfind_by を使ったコードに書き換えます。

def find
  @msg = 'please type search word...'
  @people = Array.new
  if request.post? then
    @people.push(Person.find_by(name: params[:find]))
  end
end

上述のコードでは name を検索条件としています。

例えば、 Jiro で検索します。

ruby on rails6 4

すると、 name が Jiro である最初のレコードを返します。

ruby on rails6 5

where

where は返されるレコードを制限するための条件を指定します。 SQL 文で言う WHERE に相当します。

単に where メソッドのみで使えば、指定した条件に一致するレコード群を返してくれます。

まず、 app/controller/people_controller.rbwhere を使ったコードに書き換えます。

def find
  @msg = 'please type search word...'
  @people = Array.new
  if request.post? then
    @people = Person.where(name: params[:find])
  end
end

find_by と同じく name を検索条件として、 Jiro を検索します。

ruby on rails6 4

すると、 name が Jiro であるレコード全てを返します。

ruby on rails6 6

where で使える条件式

where で使える条件式とコード例の一覧を以下の表に示します。

検索条件 コード例
文字列のみ Person.where("name = Jiro"),
Person.where("id <= #{params[:id]}")
プレースホルダーを使用した条件 Person.where("name = ?", params[:find]),
Person.where("name = ? AND id = ?", params[:find], params[:id]),
Person.where("name = :name AND id = :id", {name: params[:find], id: params[:id]})
ハッシュを使用した条件 Person.where(name: params[:find])
NOT 条件 Person.where.not(name: params[:find])
OR 条件 Person.where(name: params[:find]).or(Person.where(id: params[:id]))
サブセット条件 Person.where(id: [1,3,5])
範囲条件 Person.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)

文字列のみ

where の条件式は文字列だけで書くことも可能です。

ただし、条件で使用する数値が変動する可能性がある場合、 2 つ目のコード例のように変数をそのまま埋め込んでしまうと SQL インジェクションの脆弱性が発生する可能性があります。

そのため、渡される変数をサニタイズするために、プレースホルダーを使用した条件式か、ハッシュを使用した条件式を使用することが推奨されています。

プレースホルダーを使用した条件

最初の引数は文字列で表された条件として受け取ります。その後に続く引数は、文字列内にある ? と置き換えられます。

? をパラメータで置き換える代わりに、 3 つ目のコード例のように条件中でキー / 値のハッシュを渡すことができます。

ここで渡されたハッシュは、条件中の対応するキー / 値の部分に置き換えられます。

Rails ガイドでは配列で表された条件と表記されています。

ハッシュを使用した条件

上述の find メソッドの中ではハッシュを使用した条件で記述していますが、ハッシュによる条件は、等値、範囲、サブセットのチェックでのみ使用できます。

参考サイト

Active Record クエリインターフェイス - Railsガイド

まとめ

今回は Rails の ActiveRecord を使ってデータを検索する方法を勉強しました。

次回は Rails でバリデーションチェックを行う方法を勉強します。

それではまた、別の記事でお会いしましょう。

linkohta