ActiveRecordの基本機能とマイグレーション、バリデーション:開発現場でちゃんと使えるRails 4入門(5)(2/3 ページ)
エンタープライズ領域での採用も増えてきたRuby on Railsを使ってWebアプリケーションを作るための入門連載。最新版の4に対応しています。今回は、Railsのモデル機能を担うActiveRecordの基本的なメソッドに加え、where、order、limitを紹介。DBマイグレーションやバリデーションも。
条件に当てはまるレコードを全て取得する「where」メソッド
whereメソッドはカラムの値に条件を付けて該当するレコードを全て取得するためのメソッドです。findメソッドとは異なり、数値の範囲や文字列の一致など、検索機能を実装する際に使います。
whereメソッドの基本とプレースホルダー
例として、これまでに保存したユーザーの中から30歳以上のユーザーを求めてみましょう。
User.all.map{|user| [user.name, user.age]} # => [["アリス", 30], ["ボブ", 32], ["キャロル", 28]] users = User.where("age >= ?", 30) users.pluck(:name)# => ["アリス", "ボブ"]
このwhereメソッドでは第1引数に条件である文字列、第2引数では第1引数の文字列内の「プレースホルダー」である「?」に当てはまる値を渡しています。ここでは結果として30歳のアリスと32歳のボブがusersに含まれ、28歳のキャロルが含まれていません。
5行目に登場する「pluck」メソッドはActiveRecord(複数のオブジェクトが対象)の属性値のみを取得して配列として返却するメソッドです。
ちなみに、ここでは大きな違いはありませんが、ActiveRecordのオブジェクトの生成コストは結構大きく、pluckメソッドはActiveRecordオブジェクトを生成しないで要素を返却するため高速に動作するので、筆者は利用できる場面ではなるべく利用するようにしています。
プレースホルダーを使う意義
上の例では、引数にプレースホルダーが1個あったため引数が2個になりました。whereは条件の文字列を第1引数にとり、それにプレースホルダーが含まれていれば、その数のだけ引数を増やします。
Rubyでは文字列に値を埋め込むことができますが、プレースホルダーを使うのはSQLインジェクションを防ぐためです。プレースホルダーによって第2引数以下がエスケープされるようになっています。
whereの引数にはハッシュも使える
また、引数にはハッシュを使うこともできます。
User.where(department: '開発部') # => departmentが'開発部'のユーザー User.where(age: 30..40) # => ageが30以上、40以下のユーザー User.where(age: 30..40, department: '開発部') # => 両方の条件を同時に満たすユーザー
whereの引数にはORも使える
条件の文字列内でORを使って論理和の条件とすることもできます。
User.where("department = ? OR age > ?", '開発部', 30) # => 開発部のユーザーもしくは30歳以上のユーザー
whereはメソッドチェインでも条件を追加できる
whereはメソッドチェインでも条件を追加できます。
users = Users.where(age: 30..40) users.where(department: '開発部') # => User.where(age: 30..40, department: '開発部')と同じレコードが得られます。
他にもいろいろな機能がある
以上が基本的なwhereの使い方です。whereにはまだ異なる使い方がありますが、他の機能と併用するため、それらはいったん置いておきます。
カラムの値に基づき整列する「order」メソッド
複数のレコードを取得する際、任意のカラムの値に基づいてオブジェクトの並び方を指定したいときに使うのが「order」メソッドです。
このメソッドはwhereと同じように、モデルのクラスから呼び出すことも、whereメソッドにメソッドチェインすることもできるようになっています。
orderメソッドの基本
引数には並び順を指定するカラムとその降順か昇順かを表す文字列を渡します。
User.order('age ASC') # => 全ユーザーを年齢の昇順で取得 User.where(department: '開発部').order('age DESC') # => 開発部のユーザーを年齢の降順で取得
Rails 4からはorderの引数にHashを渡せる
Rails 4からはorderの引数にHashを渡せるようになっています。
User.order(age: :asc) # => 全ユーザーを年齢の昇順で取得
複数の並び順を指定できる
対象のカラムに同じ値が入っているオブジェクトの並び順はデフォルトでは主キー順ですが、その場合には別のカラムに基づいて、それらのオブジェクトの並び順を指定することもできます。
User.order('age ASC, created_at DESC') User.order(age: :asc).order(created_at: :desc) # => いずれもユーザーを年齢の昇順、年齢が同値ならば作成日の降順
取得するレコード数の上限を指定する「limit」メソッド
複数のレコードを取得する際、取得するレコード数の上限を指定するときに使うのがlimitメソッドです。これもwhereやorderと同じように使えます。
User.limit(10) # => ユーザーを10件まで取得 User.where(age: 30..40).limit(10) # => 30歳から40歳までのユーザーを10件まで取得
Railsにおけるデータベースのマイグレーション
「rails g(enerate) migration」コマンド
データベースの構成を変える「マイグレーション」も、ActiveRecordによって成り立っています。Railsでは、「rails generate」コマンドで生成したscaffoldやモデルにマイグレーションファイルも含まれています。また、「rails g(enerate) migration」コマンドはマイグレーションファイルだけを生成できます。
「rails g(enerate) migration」コマンドは引数に渡すマイグレーションの名前が「AddXXXToYYY」、「RemoveXXXFromYYY」のとき、「XXX」というカラムを「YYY」というテーブルに追加・削除するためのコードをマイグレーションファイルに実装してくれます。その際、マイグレーション名に続けて追加するカラムの名前と型の組も次のようにして渡します。
% rails g migration AddEmailToUser email:string
また、「rails generate」コマンドによって生成されたマイグレーションファイルはファイル名にタイムスタンプが含まれており、「rake db:migrate」などのデータベースを変更するコマンドはタイムスタンプの古い順にマイグレーションファイルを実行していきます。
マイグレーションファイルの構造
例として、サンプル「book_library」で生成したusersテーブルのマイグレーションファイルを見ると、次のようになっています。
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :department t.timestamps end end end
マイグレーションファイルは「ActiveRecord::Migration」を継承したクラスで、その中の「change」メソッドの定義によってデータベースの変更を指示します。ここで呼び出されている「create_table」メソッドはその名の通り第1引数を名前に持つテーブルを生成し、ブロックの中でカラムを定義するメソッドです。
データベース変更を指示するActiveRecordのさまざまなメソッド
ActiveRecordにはcreate_tableの他にもデータベースの変更を指示するメソッドが用意されています。
- create_table(name, options):テーブルの生成
- drop_table(name):テーブルの削除
- change_table(name, options):テーブル構成の変更
- rename_table(old_name, new_name):テーブル名の変更
- add_column(table_name, column_name, type, options):カラムの追加
- rename_column(table_name, column_name, new_column_name):カラム名の変更
- change_column(table_name, column_name, type, options):カラム型の変更
- remove_column(table_name, column_name, type, options):カラムの削除
- add_index(table_name, column_names, options):インデックスの追加
- remove_index(table_name, column: column_name):特定のカラム名のインデックスの削除
- remove_index(table_name, name: index_name):特定のインデックス名のインデックスの削除
typeで適用できる型
なお、typeで適用できる型は次の通りです。
:string :text :integer :float :decimal :datetime :timestamp :time :date :binary :boolean
Copyright © ITmedia, Inc. All Rights Reserved.