【Rails】Active Record(モデル)の書き方《基本篇》

2021年4月16日 13:14

はじめに

ActiveRecord(モデル)は、MVCモデルのMに相当します。モデルはRailsアプリとデータベースの橋渡し役を担います。データベースの種類(MySQL、MariaDB、PostgreSQL、SQLite)にかかわらず、統一的なインターフェースでデータの操作(取得、作成、更新、削除)を行うことができます。

本記事では、ActiveRecord(モデル)の使い方についてまとめています。

モデルの基本

ORMフレームワーク

ORM (Object Relational Mapping) とは、データベースの種類を気にすることなくデータの操作(取得、作成、更新、削除)が行えること、またそのインターフェースのことをいいます。Railsはサードパーティ製のORMフレームワークを導入しなくても、ActiveRecord(モデル)がORMフレームワークの役割を担ってくれます。

モデルには以下の特徴があります。

  • コントローラーまたはビューからモデルを介してデータベースにアクセスできる。
  • 統一的なインターフェースでデータの操作(取得、作成、更新、削除)が行える。
  • 関連付けられているモデル同士の相互操作が容易に行える。
  • データ永続化の前にバリデーションチェックが行える。

モデルの作成

モデルを作成するには以下のコマンドを実行します。

$ rails generate model User name:string

モデル名は単数形(User)を指定しますが、実際に作成されるテーブル名は複数形(users)です。モデル名の後にカラム名と型をいくつでも指定することができます。

モデル作成コマンドを実行するとモデルの作成と同時にマイグレーションファイルも作成されます。作成されたマイグレーションファイルを基にマイグレーションを行うことで、データベースにテーブルが作成されます。マイグレーションについては以下の記事を参照してください。

モデルの削除

モデルを削除するには以下のコマンドを実行します。

$ rails destroy model User

モデル削除コマンドを実行してもデータベースのテーブルは削除されません。テーブルを残したままモデルを削除してしまうと不整合が起こるので、必ず該当のマイグレーションをロールバックなどして状態をdownにしてからモデルを削除してください。

データの操作

データの操作(取得、作成、更新、削除)はコントローラーとビューのどちらからでも行うことができます。ただし、特段の理由がなければ(MVCモデルの理念に従い)コントローラーから行うようにしたほうがいいでしょう。

データの取得

データを取得するメソッドはたくさんあります。ここでは、よく使うであろうメソッドのみ紹介します。

find

findは指定した主キーの値に一致するデータを取得します。主キーを条件にしているのでデータは必ず1件に絞り込まれます。

@user = User.find(10)

find_by

find_byは指定したカラムの値に一致するデータを取得します。条件によっては1件に絞り込まれるとは限りませんが、条件に一致したデータのうち、最初の1件のみを取得します。条件はカンマ(,)で区切って複数指定することができます。

@user = User.find_by(gender: 'male')

where

wherefind_byと似ていますが、条件に一致したデータをすべて取得する点が異なります。

@users = User.where(gender: 'male')

whereは条件を通常のSQLのように書くこともできます。値には引数を与えることもできます。

@users = User.where("gender = 'male' AND age > ?", params[:age])

# 以下はSQLインジェクションの危険があるため避ける
# @users = User.where("gender = 'male' AND age > #{params[:age]}")

order

orderは取得したデータを並べ替えます。ASC(昇順:デフォルト)またはDESC(降順)を指定します。

@users = User.all.order(name: :asc, updated_at: :desc)

find_each

find_eachは複数データをブロック(デフォルトで1000件)で取得し、ブロック単位で繰り返し処理を行います。最初のブロックの処理が完了したら次のブロックを取得し、また繰り返し処理を行います。最後のデータになるまでこれを繰り返します。

User.all.find_each do |user|
  ...
end

# 以下の書き方はメモリ消費が大きいので避ける
# User.all.each do |user|
#   ...
# end

Enum

値がenum型で設定されている場合、キーの名前を繋げるだけでデータを取得することができます。

# モデルに以下が定義されているとする
# enum gender: [male: 0, female: 1]

@users_male = User.male
@users_female = User.female

集計関数

一般的なSQLで用いられる集計関数(件数、平均、最小値、最大値、合計)を使うことができます。

@count = User.count
@average = User.average(:age)
@minimum = User.minimum(:age)
@maximum = User.maximum(:age)
@sum = User.sum(:age)

データの作成

データを作成するにはcreateまたはnewsaveを使います。createの代わりにcreate!を使うと、データの作成に失敗したときにActiveRecord::RecordInvalid例外が発生します。

User.create(name: 'Jane', gender: 'female', age: 20)
User.create!(name: 'Jane', gender: 'female', age: 20)

@user = User.new(name: 'Jane', gender: 'female', age: 20)
@user.save
@user.save!

データの更新

データを更新するにはupdateを使います。updateの代わりにupdate!を使うと、データの更新に失敗したときにActiveRecord::RecordInvalid例外が発生します。

@user = User.find(params[:id])
@user.update(age: 30)
@user.update!(age: 30)

# 以下の書き方でもOK
# @user = User.find(params[:id])
# @user.age = 30
# @user.save

複数データを一気に更新するにはupdate_allを使います。

@users = User.find_by(gender: 'female')
@users.update_all(age: params[:new_age])

データの削除

データを削除するにはdestroyまたはdestroy_byを使います。

@user = User.find(params[:id])
@user.destroy

User.destroy_by(id: params[:id])

複数データを一気に削除するにはdestroy_allを使います。

User.destroy_all

モデルの関連付け

モデル同士が密接な関係にあるとき、モデルの関連付けを明示的に行うことでRailsによる様々な恩恵を受けることができます。例えば、特定のArticleが複数のCommentを所持するとき(=複数のCommentは特定のArticleに従属するとき)、Articleが削除されたらCommentも削除されなければなりません。モデルの関連付けを行っておくとCommentの削除はRailsが自動で行ってくれます。

関連付けの種類

Railsで行える関連付けの種類は以下の通りです。

関連付け 用途 意味
belongs_to 1対1 特定のモデルが特定のモデルに従属する。
has_one 1対1 特定のモデルが特定のモデルを所持する。
has_many 1対多 特定のモデルが複数のモデルを所持する。
has_many :through 多対多 複数のモデルが複数のモデルを所持する。
has_one :through 1対1 特定のモデルが特定のモデルを所持する。
has_and_belongs_to_many 多対多 複数のモデルが複数のモデルを所持する。

1対1の関連付け

1対1の関連付けを行うには、一方のモデルにbelongs_toを設定し、もう一方のモデルにhas_oneを設定します。belongs_tohas_oneも対象は特定のモデルなので、指定するモデル名は単数形にします。

belongs_tohas_oneをどちらのモデルに設定するかは、モデルの意味を考える必要があります。以下の例だと、「給料は従業員を所持する」ではなく「従業員は給料を所持する」と考えたほうが自然なので、Employeehas_oneを設定し、Salarybelongs_toを設定します。

# 従業員モデル
has_one :salary, dependent: destroy

# 給料モデル
belongs_to :employee

belongs_toを設定するテーブルには外部キーカラムを追加する必要があります。以下はsalariesテーブルにemployeeカラムを追加し、外部キーを設定している例です。

# テーブル作成のマイグレーション
t.references :employee, null: false, foreign_key: true

# カラム追加のマイグレーション
add_reference :salaries, :employee, foreign_key: true

1対多の関連付け

1対多の関連付けを行うには、一方のモデルにbelongs_toを設定し、もう一方のモデルにhas_manyを設定します。has_manyの対象は複数のモデルなので、指定するモデル名は複数形にします。

# 記事モデル
has_many :comments, dependent: destroy

# コメントモデル
belongs_to :article

多対多の関連付け

多対多の関連付けを行うには、一方のモデルにhas_many :throughを設定し、もう一方のモデルにもhas_may :throughを設定します。そして、それぞれの中間となるモデルにbelongs_toを設定します。

# 記事モデル
has_many :tagmaps, dependent: destroy
has_many :tags, through: tagmaps

# タグマップモデル
belongs_to :article
belongs_to :tag

# タグモデル
has_many :tagmaps, dependent: destroy
has_many :articles, through: tagmaps

多対多の関連付けはhas_and_belongs_to_manyを使う方法もあります。

# 記事モデル
has_and_belongs_to_many :tags

# タグモデル
has_and_belongs_to_many :articles

has_and_belongs_to_many関連付けを使った場合、中間となる結合テーブルを作成する必要があります。このテーブルに主キーを設定すると関連付けが正常に動かないことがあるため、必ずid: falseを設定する必要があります。

class CreateArticlesTagsJoinTable < ActiveRecord::Migration[6.0]
  def change
    create_table :articles_tags, id: false do |t|
      t.bigint :article_id
      t.bigint :tag_id
    end

    add_index :articles_tags, :article_id
    add_index :articles_tags, :tag_id
  end
end

create_join_tableメソッドを使うこともできます。

class CreateArticlesTagsJoinTable < ActiveRecord::Migration[6.0]
  def change
    create_join_table :articles, :tags do |t|
      t.index :article_id
      t.index :tag_id
    end
  end
end

関連付けモデルのデータ操作

モデルに適切な関連付けを設定していると、一方のモデルのインスタンスから関連付けられているもう一方のモデルのデータを操作することができます。

@employee = Employee.find(params[:id])

# データの取得
@salary = @employee.salary

# データの作成
@salary = @employee.create_salary(base: params[:base], reward: params[:reward])

# データの更新
@employee.salary = @employee.build_salary(base: params[:base], reward: params[:reward])
@employee.save

まとめ

Webアプリケーションにデータベースはほとんど必須と言っても過言ではありません。実際、世の中に存在するほとんどのWebアプリケーションはデータベースを持ち独自のデータを保持しています。WebアプリケーションにとってなくてはならないデータベースとRailsアプリを繋ぐActiveRecord(ビュー)の使い方を把握しておく必要があります。

本記事を参考にして、ActiveRecord(ビュー)の使い方を覚えていただければと思います。

関連記事

【Rails】Railsアプリのデバッグ《マルチデバイス篇》
# はじめに 近年のWebアプリはレスポンシブ対応が当たり前になっています。最低でもPCとスマートフォンに対応したデザイン、ときにはその中間のタブレットに対応したデザインなんかも作成する必要があります。 Webアプリの開発はPCを使って行う [...]
2021年5月23日 13:02
【Rails】Railsアプリのデバッグ《Better Errors篇》
# はじめに Railsアプリの開発中になんらかのエラーが発生すると、デフォルトでは以下のような画面が表示されます(画像をクリックすると拡大します)。 <a class="gallery" data-group="gallery" href [...]
2021年5月22日 19:42
【Rails】Railsアプリのデバッグ《byebug篇》
# はじめに Ruby on Railsに限りませんが、アプリの開発中にはエラーは付き物です。なにかしらのエラーが発生したときに、エラーの原因を特定しエラー箇所を修正することをデバッグと言います。Railsではデバッグの手助けとなる機能があらかじ [...]
2021年5月22日 15:30
【Rails】レンダリング(renderメソッド)でアンカー指定を行う
# はじめに 通常、Railsでアンカー付きのリクエストを発生させるには`redirect_to`を使います。 ```rb redirect_to root_path(anchor: 'target') ``` では、`rende [...]
2021年5月20日 10:47
【Rails】Bundler 2.2.x以降は開発者が適切なプラットフォームを追加する必要がある
# 事象 昔作ったRailsアプリを久しぶりに修正しデプロイしようとしたところ、以下のエラーが出力されました。 ```bash # 実行コマンド Running $HOME/.rbenv/bin/rbenv exec bundle ch [...]
2021年5月18日 16:18