【Rails入門】モデル(model)の基本まとめ

Ruby on Rails(以降、Rails)は、MVC呼ばれるデザインパターンを採用したフレームワークです。

この記事では、そのMVCのうちのM、すなわちModelについて解説します。

  • そもそもMVCとは
  • そしてModelとは
  • どのようにしてModelを作成するか

といった基本的な内容から、

  • データの取り出し方
  • データの更新方法
  • データの新規作成

などの実務的な内容に関しても解説していきます。Modelの基礎を正しく理解し、スムーズに応用できるように、わかりやすく解説します!

Modelとは

Modelは、MVCを構成するコンポーネントの1つです。MVCは、以下の3つのコンポーネント(構成要素)から構成されるデザインパターンです。

コンポーネント(構成要素)説明備考
Model(モデル)データベースを取り扱うデータベースへの格納方法は、Modelに隠ぺいする
View(ビュー)画面表示を取り扱う表示方法は、Viewに隠ぺいする
Controller(コントローラー)(ユーザーの入力を受けて)ModelとViewにアレコレ指示するデータベースへの格納方法や表示方法は知らない

Railsでは、Rails標準のライブラリであるActive Recordを利用して、Modelを実装します。つまり、Railsでは、Active Recordを使って、データベース(テーブル)にデータを格納したり更新したり、データベース(テーブル)に格納したデータを検索したりできるということです。

Modelの使い方を理解するために環境を準備しよう!

まずはRailsの開発環境を構築しよう

Modelの使い方を理解するために、Railsの開発環境を構築しておきましょう。Railsの開発環境の構築方法は、以下の記事で解説していますので、ぜひご覧ください。

初心者でもかんたん!Ruby on Rails の開発環境の構築手順(Mac/Windows 両対応)
更新日 : 2019年8月9日

この記事では、app/samurai/model-demoディレクトリを作成して開発環境を構築した場合を例に、説明を続けます。

hirb gemとhirb-unicode gemをインストールしよう

この後、Modelの使い方を確認する際、Railsコンソールを使用します。Railsコンソールで出力したデータの見栄えを良くにするために、以下の2つのgemをインストールしましょう。

gem説明
hirb gem出力結果を表形式で出力する
hirb-unicode gemマルチバイト文字の表示を補正する

(1)Gemfileの最終行に以下の内容を追記します。

gem 'hirb'
gem 'hirb-unicode'

(2)以下のコマンドを入力します。

bundle install

これで、hirb gemとhirb-unicode gemがインストールされました。

Modelを作成する

RailsでModelを作成するには、以下の2つを作成します。

  • モデルクラス(Active Record)
  • データベース(テーブル)

この記事では、movieというModelと、directorというModelを作成します。movie Modelでは、以下の情報を格納します。

カラムデータ型説明
titlestring映画のタイトル
publisheddate映画が公開された日付
salesbigint映画の興行収入(単位:ドル)
rankinteger興行収入順位
directorreferences
(belongs_toでも同じ)
監督(外部キー)

director Modelでは、以下の情報を格納します。

カラムデータ型説明
namestring監督名

Railsで上記のようなModelを簡単に作成するために、bin/rails generate modelコマンドと、bin/rails db:migrateコマンドが用意されています。まずは、bin/rails generate modelコマンドの基本構文を説明します。

rails generate model name field:type [...]
パラメータ説明
name生成するモデルクラスの名前
fieldフィールド名
typeデータの型など
代表的な型は以下のとおりです。
・string
・date
・integer
・bigint
・references / belongs_to

基本構文をチラ見したら、bin/rails generate modelコマンドの使用例を見てみましょう。

(1)「端末」を起動して、以下のコマンドを1行ずつ順番に入力します。

cd app/samurai/model-demo/
bin/rails generate model movie title:string published:date sales:bigint rank:integer director:references

実行結果:

Running via Spring preloader in process 3683
      invoke  active_record
      create    db/migrate/20180705061405_create_movies.rb
      create    app/models/movie.rb
      invoke    test_unit
      create      test/models/movie_test.rb
      create      test/fixtures/movies.yml

実行結果にあるとおり、4つのファイルが作成されていますが、この記事では、以下の3つのファイルに注目します。

ファイル名ファイルの種類説明
db/migrate/
20180705061405_create_movies.rb
マイグレーションファイルデータベース(テーブル)の作成方法を記述したファイルです。
ファイル名の先頭の数字部分は、コマンドを実行した日時により異なります。
app/models/movie.rbモデルクラスファイルモデルクラスを定義するファイルです。
test/fixtures/movies.ymlフィクスチャファイルデータベース(テーブル)に格納するデータを記述するファイルです。

各ファイルの内容は以下のとおりです。マイグレーションファイル(db/migrate/20180705061405_create_movies.rb)

class CreateMovies < ActiveRecord::Migration[5.1]
  def change
    create_table :movies do |t|
      t.string :title
      t.date :published
      t.bigint :sales
      t.integer :rank
      t.references :director, foreign_key: true

      t.timestamps
    end
  end
end

モデルクラス(app/models/movie.rb)

class Movie < ApplicationRecord
  belongs_to :director
end

フィクスチャファイル(test/fixtures/movies.yml)

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
  title: MyString
  published: 2018-07-05
  sales:
  rank: 1
  director: one

two:
  title: MyString
  published: 2018-07-05
  sales:
  rank: 1
  director: two

続けて、director(外部キー)が参照するテーブルも作成しましょう。

(2)以下のコマンドを入力します。

bin/rails generate model director name:string

実行結果:

Running via Spring preloader in process 3775
      invoke  active_record
      create    db/migrate/20180705061458_create_directors.rb
      create    app/models/director.rb
      invoke    test_unit
      create      test/models/director_test.rb
      create      test/fixtures/directors.yml

movieと同様、4つのファイルが作成されます。

次に、作成されたマイグレーションファイルを元に、データベース(movieテーブル、directorテーブル)を作成します。

(2)以下のコマンドを入力します。

bin/rails db:migrate

実行結果:

== 20180705061405 CreateMovies: migrating =====================================
-- create_table(:movies)
   -> 0.0118s
== 20180705061405 CreateMovies: migrated (0.0120s) ============================

== 20180705061458 CreateDirectors: migrating ==================================
-- create_table(:directors)
   -> 0.0017s
== 20180705061458 CreateDirectors: migrated (0.0018s) =========================

以上で、モデルクラス(Active Record)とデータベース(movieテーブル、directorテーブル)が作成され、すなわちmovie Modelとdirector Modelが作成されたことになります。

マイグレーションファイルを作成しない方法について(--skip-migration)

ちなみに、マイグレーションファイルを作成せずに、それ以外のファイルだけを作成する場合は、以下のように--skip-migrationを指定します。

bin/rails generate model movie title:string published:date sales:bigint rank:integer director:references --skip-migration

実行結果:

Running via Spring preloader in process 4100
      invoke  active_record
      create    app/models/movie.rb
      invoke    test_unit
      create      test/models/movie_test.rb
      create      test/fixtures/movies.yml

上で紹介した実行結果と比べると、マイグレーションファイルが作成されていないことがわかりますね。

Modelに関する命名規約について

Modelに関連する命名規約をまとめました。頭文字の大文字/小文字と、単数形/複数形の違いを覚えておくとスムーズに作業を進められるでしょう。

ファイルの種類命名規約
モデルクラスファイル名頭文字が小文字、単数形movie.rb
モデルクラス名頭文字が大文字、単数形Movie
テーブル名頭文字が小文字、複数形movies

モデルクラスをカスタマイズする

bin/rails generate modelコマンドで作成されるモデルクラスは、極めて基本的な内容しか書かれていません。

モデルクラスには、データベースを取り扱う(データベースへの格納方法は、Modelに隠ぺいする)という役割がありますので、その役割から逸脱しないようにプログラムを書いていきましょう。ここでは、モデルクラスでよく使う機能を紹介します。

検証機能を付与する(validates)

モデルクラスをカスタマイズして、検証機能を付与できます。検証機能について詳しくは、以下の記事を参考にしてください。

【Rails入門】バリデーション(validations)の使い方まとめ
更新日 : 2018年6月18日

クエリを定義する(scope)

モデルクラスでよく使うクエリを、モデルクラスファイルで定義できます。クエリを定義する方法について詳しくは、以下の記事を参考にしてください。

【Rails入門】scopeの使い方まとめ
更新日 : 2017年7月15日

Modelを削除する

もし間違ったModelを作成してしまった場合は、モデルクラスとテーブルを削除します。

モデルクラスを削除する

モデルクラスを削除するには、以下のコマンドを入力します。

bin/rails destroy model movie

実行結果:

Running via Spring preloader in process 3946
      invoke  active_record
      remove    db/migrate/20180705061405_create_movies.rb
      remove    app/models/movie.rb
      invoke    test_unit
      remove      test/models/movie_test.rb
      remove      test/fixtures/movies.yml

テーブルを削除する

モデルクラスを削除したら、テーブルを削除しましょう。

bin/rails db:drop:all

実行結果:

Dropped database 'db/development.sqlite3'
Database 'db/test.sqlite3' does not exist
Database 'db/production.sqlite3' does not exist

ここでは、すべてのテーブルを削除しましたが、必要なテーブルがある場合は、以下のコマンドを実行すると良いでしょう。

bin/rails db:migrate:reset

モデルクラスを利用する

Modelを作成できたところで、Modelを扱ってみましょう。RailsでModelを扱うには、モデルクラスを利用して、テーブルに格納したデータを検索したり更新します。

テストデータを準備する

まずは、テストデータを準備します。この記事では、テーブルへテストデータを格納するために、フィクスチャを利用します。

(1)test/fixtures/movies.ymlを以下のように編集します。

変更前:

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
  title: MyString
  published: 2018-07-05
  sales:
  rank: 1
  director: one

two:
  title: MyString
  published: 2018-07-05
  sales:
  rank: 1
  director: two

変更後:

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
  title: アバター
  published: 2009-12-18
  sales: 2787965087
  rank: 0
  director: jc

two:
  title: タイタニック
  published: 1997-12-19
  sales: 2187463944
  rank: 0
  director: jc

three:
  title: スター・ウォーズ/フォースの覚醒
  published: 2015-12-18
  sales: 2068223624
  rank: 0
  director: jja

director:に指定したjcやjjaは、次のtest/fixtures/directors.ymlで指定するラベルに対応しています。

(2)test/fixtures/directors.ymlを以下のように編集します。

変更前:

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

one:
  name: MyString

two:
  name: MyString

変更後:

# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html

jc:
  name: James Cameron

jja:
  name: J.J. Abrams

jr.ar:
  name: Joe Russo, Anthony Russo

以上がテストデータです。このテストデータをテーブルに格納しましょう。

(3)以下のコマンドを入力します。

bin/rails db:fixtures:load

テーブルに格納できたことを確認しましょう。

(4)以下のコマンドを1行ずつ順番に入力します。

bin/rails console
Hirb.enable
Movie.all

実行結果:

  Movie Load (1.4ms)  SELECT "movies".* FROM "movies"
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| id        | title                  | published  | sales      | rank | director_id | created_at            | updated_at             |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| 113629430 | スター・ウォーズ/フ... | 2015-12-18 | 2068223624 | 0    | 530990343   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
| 298486374 | タイタニック           | 1997-12-19 | 2187463944 | 0    | 175153456   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
| 980190962 | アバター               | 2009-12-18 | 2787965087 | 0    | 175153456   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
3 rows in set

(5)以下のコマンドを1行ずつ順番に入力します。

Director.all

実行結果:

  Director Load (0.2ms)  SELECT "directors".* FROM "directors"
+-----------+--------------------------+-------------------------+-------------------------+
| id        | name                     | created_at              | updated_at              |
+-----------+--------------------------+-------------------------+-------------------------+
| 175153456 | James Cameron            | 2018-07-05 06:25:10 UTC | 2018-07-05 06:25:10 UTC |
| 530990343 | J.J. Abrams              | 2018-07-05 06:25:10 UTC | 2018-07-05 06:25:10 UTC |
| 615043578 | Joe Russo, Anthony Russo | 2018-07-05 06:25:10 UTC | 2018-07-05 06:25:10 UTC |
+-----------+--------------------------+-------------------------+-------------------------+
3 rows in set

無事にテストデータが格納されていますね!

(6)以下のコマンドを入力します。

exit

検索してデータを取り出す

モデルクラスを利用して、テーブルからデータを検索して取り出す方法を紹介します。ここではRailsコンソールを使っていますが、モデルクラスファイルでも同様のコードでデータを検索して取り出せます。

(1)以下のコマンドを入力します。

bin/rails console

ここでは、whereメソッドを使って、2001-01-01以降に公開された映画のデータを取り出してみましょう。

(2)以下のコマンドを1行ずつ順番に入力します。

Hirb.enable
Movie.where('published > "2001-01-01"')

実行結果:

  Movie Load (1.6ms)  SELECT "movies".* FROM "movies" WHERE (published > "2001-01-01")
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| id        | title                  | published  | sales      | rank | director_id | created_at            | updated_at             |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| 113629430 | スター・ウォーズ/フ... | 2015-12-18 | 2068223624 | 0    | 530990343   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
| 980190962 | アバター               | 2009-12-18 | 2787965087 | 0    | 175153456   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
2 rows in set

該当するデータが2件取得できていますね。

(3)以下のコマンドを入力します。

exit

データを更新する

次に、テーブルのデータを更新してみましょう。やはりRailsコンソールを使います。

(1)以下のコマンドを入力します。

bin/rails console

ここでは、whereメソッドを使って、title(映画のタイトル)が「アバター」のデータを取り出して、rank(興行収入順位)を1にしてみましょう。

(2)以下のコマンドを1行ずつ順番に入力します。

Hirb.enable
Movie.where('title = "アバター"').update(rank: '1')

実行結果:

  Movie Load (1.8ms)  SELECT "movies".* FROM "movies" WHERE (title = "アバター")
   (0.1ms)  begin transaction
  Director Load (0.1ms)  SELECT  "directors".* FROM "directors" WHERE "directors"."id" = ? LIMIT ?  [["id", 175153456], ["LIMIT", 1]]
  SQL (0.8ms)  UPDATE "movies" SET "rank" = ?, "updated_at" = ? WHERE "movies"."id" = ?  [["rank", 1], ["updated_at", "2018-07-05 06:27:35.943715"], ["id", 980190962]]
   (16.1ms)  commit transaction
+-----------+----------+------------+------------+------+-------------+-------------------------+-------------------------+
| id        | title    | published  | sales      | rank | director_id | created_at              | updated_at              |
+-----------+----------+------------+------------+------+-------------+-------------------------+-------------------------+
| 980190962 | アバター | 2009-12-18 | 2787965087 | 1    | 175153456   | 2018-07-05 06:25:10 UTC | 2018-07-05 06:27:35 UTC |
+-----------+----------+------------+------------+------+-------------+-------------------------+-------------------------+
1 row in set

rankの値が「0」から「1」に変更されました。

(3)以下のコマンドを入力します。

exit

データを作成する

最後に、新しいデータを作成してテーブルに追加してみましょう。ここでもRailsコンソールを使います。

(1)以下のコマンドを入力します。

bin/rails console

(2)以下のコマンドを1行ずつ順番に入力します。

Hirb.enable
movie = Movie.new(title: 'アベンジャーズ/インフィニティ・ウォー', published: '2018-04-27', sales: '2036816820', rank: '5', director_id: '175153456')

実行結果:

+----+---------------------------------------+------------+------------+------+-------------+------------+------------+
| id | title                                 | published  | sales      | rank | director_id | created_at | updated_at |
+----+---------------------------------------+------------+------------+------+-------------+------------+------------+
|    | アベンジャーズ/インフィニティ・ウォー | 2018-04-27 | 2036816820 | 5    | 175153456   |            |            |
+----+---------------------------------------+------------+------------+------+-------------+------------+------------+
1 row in set

データベース(テーブル)に保存します。

(3)以下のコマンドを入力します。

movie.save

実行結果:

   (0.1ms)  begin transaction
  Director Load (0.1ms)  SELECT  "directors".* FROM "directors" WHERE "directors"."id" = ? LIMIT ?  [["id", 175153456], ["LIMIT", 1]]
  SQL (1.4ms)  INSERT INTO "movies" ("title", "published", "sales", "rank", "director_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?)  [["title", "アベンジャーズ/インフィニティ・ウォー"], ["published", "2018-04-27"], ["sales", 2036816820], ["rank", 5], ["director_id", 175153456], ["created_at", "2018-07-05 06:29:34.358453"], ["updated_at", "2018-07-05 06:29:34.358453"]]
   (6.6ms)  commit transaction
=> true

新しいデータが追加されていることを確認しましょう。

(4)以下のコマンドを入力します。

Movie.all

実行結果:

  Movie Load (0.1ms)  SELECT "movies".* FROM "movies"
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| id        | title                  | published  | sales      | rank | director_id | created_at            | updated_at             |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
| 113629430 | スター・ウォーズ/フ... | 2015-12-18 | 2068223624 | 0    | 530990343   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
| 298486374 | タイタニック           | 1997-12-19 | 2187463944 | 0    | 175153456   | 2018-07-05 06:25:1... | 2018-07-05 06:25:10... |
| 980190962 | アバター               | 2009-12-18 | 2787965087 | 1    | 175153456   | 2018-07-05 06:25:1... | 2018-07-05 06:27:35... |
| 980190963 | アベンジャーズ/イン... | 2018-04-27 | 2036816820 | 5    | 175153456   | 2018-07-05 06:29:3... | 2018-07-05 06:29:34... |
+-----------+------------------------+------------+------------+------+-------------+-----------------------+------------------------+
4 rows in set

データが4つになりましたね!

まとめ

この記事では、Modelの基礎として、Modelの役割を説明しました。また、データの検索や更新を行う方法など、実務的な内容についても説明しました。Modelには、この記事で説明した内容のほかにも様々な役割や使い方があり、学ぶ範囲がとても広いテーマです。

まずは、この記事でまとめたModelの基礎をしっかり理解したうえで、さらに難しい内容に取り組んでみてはいかがでしょうか?もし、Modelの基礎を忘れてしまったら、この記事を思い出してくださいね!

LINEで送る
Pocket

SEからWebエンジニアへ転職した理由

侍エンジニア塾卒業生の小池さんは、以前は社内SEとして約5年ほど勤務していました。しかし業務内容は社内のヘルプデスク対応など、プログラムを書く仕事は全くなかったそうです。

SEながらプログラムを書けない現状に「将来仕事がなくなるんじゃないか」と不安を感じ、プログラミング学習を決意。

弊社スクールで学習し、無事ベンチャー企業のプログラマーとして転職に成功しました。そんな小池さんの学習法や転職体験談を伺いましたので、是非ご覧ください。

「プログラミングができないSEは仕事がなくなる」不安を感じたSEが未経験から転職成功するまで
更新日 : 2019年10月7日

書いた人

侍テック編集部

侍テック編集部

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説