前 基礎Ruby on Rails Chapter4 データベースとモデル
次 基礎Ruby on Rails Chapter5 RESTとルーティング
レコードの作成と更新
Railsコンソール
- Railsコンソールを起動するには、
bin/rails c
コマンドを実行する。 -
Member.count
で、membersテーブルの件数をカウントする。
$ bin/rails c
Loading development environment (Rails 5.2.1)
irb(main):001:0> Member.count
(0.2ms) SELECT COUNT(*) FROM "members"
=> 0
irb(main):002:0>
レコードの作成
-
member = Member.new
でインスタンス作成、属性を設定して、saveメソッドでレコードを保存する。
irb(main):002:0> member = Member.new
=> #<Member id: nil, number: nil, name: nil, full_name: nil, email: nil, birthday: nil, sex: 1, administrator: false, created_at: nil, updated_at: nil>
irb(main):003:0> member.number=1
=> 1
irb(main):004:0> member.name="Taro"
=> "Taro"
irb(main):005:0> member.save
(0.0ms) begin transaction
Member Create (6.1ms) INSERT INTO "members" ("number", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["number", 1], ["name", "Taro"], ["created_at", "2018-09-20 12:03:44.207546"], ["updated_at", "2018-09-20 12:03:44.207546"]]
(14.4ms) commit transaction
=> true
irb(main):006:0>
- レコードの作成方法は以下のいずれかが考えられる。
-
member = Member.new
→member.number = 1
→member.name = "Taro"
→member.save
-
member = Member.new(number: 1, name: "Taro")
→member.save
-
member = Member.new
→member.assign_attributes(number: 1, name: "Taro")
→member.save
member = Member.create(number: 1, name: "Taro")
-
-
save
メソッドはバリデーションが失敗した場合はfalseを返す。 -
save!
メソッドは、バリデーションに失敗した場合は例外が発生する。
レコードの更新
- レコードの更新方法は以下のいずれかが考えられる。
-
member = Member.first
→member.number = 41
→member.save
-
member = Member.first
→member.assign_attributes(number: 51, name: "Ichiro")
→member.save
-
member = Member.first
→Member.update_attributes(number: 55, name: "Hideki")
-
irb(main):006:0> member = Member.first
Member Load (5.4ms) SELECT "members".* FROM "members" ORDER BY "members"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Member id: 1, number: 1, name: "Taro", full_name: nil, email: nil, birthday: nil, sex: 1, administrator: false, created_at: "2018-09-20 12:03:44", updated_at: "2018-09-20 12:03:44">
irb(main):007:0> member.assign_attributes(number: 51, name: "Ichiro")
=> nil
irb(main):008:0> member.save
(0.1ms) begin transaction
Member Update (1.5ms) UPDATE "members" SET "number" = ?, "name" = ?, "updated_at" = ? WHERE "members"."id" = ? [["number", 51], ["name", "Ichiro"], ["updated_at", "2018-09-20 12:16:35.031549"], ["id", 1]]
(11.1ms) commit transaction
=> true
シードデータの投入
シードデータの使い方
- db/seeds.rbに、シードデータを作成するスクリプトを書いて、
bin/rails db:seed
コマンドを実行すれば、シードデータが保存される。 - 本番環境の場合は、
bin/rails db:seed RAILS_ENV=production
のように、環境変数を付加する。
db/seeds.rb
Member.create(number: 1, name: "Taro", administrator: true)
$ bin/rails db:seed
モード別のシードデータ
- db/seeds/developmentディレクトリの下に、
members.rb
があれば、それをrequireメソッドで実行する。
db/seeds.rb
table_names = %w(members) # ほかに入れたいテーブルがあれば、ここに空白区切りで追加して、rbファイルも作る
table_names.each do |table_name|
path = Rails.root.join("db/seeds", Rails.env, table_name + ".rb")
if File.exist?(path)
puts "Creating #{table_name}..."
require path
end
end
- memberにデータを投入するプログラム
db/seeds/development/members.rb
names = %w(Taro Jiro Hana John Mike Sophy Bill Alex Mary Tom)
fnames = ["佐藤", "鈴木", "高橋", "田中"]
gnames = ["太郎", "次郎", "花子"]
0.upto(9) do |idx|
Member.create(
number: idx + 10,
name: names[idx],
full_name: "#{fnames[idx % 4]} #{gnames[idx % 3]}",
email: "#{names[idx]}@example.com",
birthday: "1981-12-01",
sex: [1, 1, 2][idx % 3],
administrator: (idx == 0)
)
end
シードデータの再投入
# データベースを破棄→db/schema.rbを実行→シードデータの投入
$ bin/rails db:reset
# データベースを破棄→最初からマイグレーションをやり直す→シードデータの投入
$ bin/rails db:migrate:reset db:seed
- db:rebuildタスク
lib/tasks/database.rake
namespace :db do
desc "Rebuild the development database from scratch"
task :rebuild => :environment do
sh "rm -f db/development.sqlite3"
Rake::Task["db:migrate"].invoke
Rake::Task["db:seed"].invoke
end
end
- 上記コマンドを使って、シードデータの再投入をする。
$ bin/rails db:rebuild
findとfind_by
findメソッド
-
find(キーの値)
で、レコードを1件取得する。 - 該当データが無い場合、例外ActiveRecord::RecordNotFount発生。
find_byメソッド
-
find_by(項目名1: 値1, 項目名2: 値2, ・・・)
で、最初に一致したレコードを1件取得する。 - 該当データが無い場合、nilが返る。
クエリーメソッドとリレーションオブジェクト
クエリーメソッドとリレーションオブジェクト
- whereメソッドは、条件に一致する複数のレコードを取り出す。
- 実際に返すのは、配列ではなくActiveRecord::Relationクラスのオブジェクト。
-
Member.where(name: "Taro")
、Member.where("number < 20")
のように書ける。
検索が実行されるタイミング
- whereメソッドは、呼び出しただけでは検索は実行されない。検索が実行されるのはデータが必要になった時。
-
@members = Member.where(sex: 2).load
のようにloadメソッドを使うと、即座に実行される。 - lengthメソッドは検索を実行して、配列を作ったうえで配列の長さを返す。必ず結果を使うのなら、こちらがいい。
- sizeメソッドはcountメソッド呼び出して、SQLで件数をカウントする。件数によって結果を取得しないのなら、こちらがいい。
クエリーメソッドの重ね合わせ
- whereをAND条件で結びつける。
# 2つの検索条件をANDで結びつける
members = Member.where(name: "Taro")
members = members.where("number < 20")
# 1行でまとめる
members = Member.where(name: "Taro").where("number < 20")
- whereとorderに組み合わせ
# ソート順を指定する。
members = Member.where(sex: 2).order("number")
# 引数をハッシュにする書き方
members = Member.where(sex: 2).order(number: :desc)
ファインダーメソッドとの組み合わせ
- firstメソッドは先頭から1つだけ取り出す。
- lastメソッドは最後から1つ取り出す。
- firstとlastはソート順をつけること。付けないと結果が不定になる。
- そのほか、find(1)、find_by(id:1)。
members = Member.where(sex: 2).order("number").first
whereメソッドの便利な使い方
-
カラム値:配列
というハッシュを渡すと、どれかと同じという検索条件を指定できる。
# 配列で取り出す。
members = Member.where(number: [15,17,19])
members.map(&:name)
# = ["Sophy","Alex","Tom"]
-
カラム値:範囲オブジェクト
というハッシュを渡すと、その範囲という検索条件を指定できる。
# 範囲で取り出す。
members = Member.where(number: 12..14)
members.map(&:name)
-
not
メソッドは、〇〇でないという検索条件を指定できる。
# 範囲で取り出す。
members = Member.where.not(name: "Taro")
プレースホルダー
-
?
に、変数の値を埋め込む。SQLインジェクション対策。
name = "Taro"
members = Member.where("name = ?", name)
集計用のメソッド
-
average(カラム名)
、count
、maximum(カラム名)
、minimum(カラム名)
、sum(カラム名)
で集計をすることができる。
Member.maximum("number")
# = 19
Member.where(sex: 1).count
# = 7
- SQLを直接書くには、
find_by_sql
メソッドを使う
members = Member.find_by_sql("SELECT * FROM members WHERE number = 11")
# プレースホルダーを使うには、配列で指定する
members = Member.find_by_sql(["SELECT * FROM members WHERE name = ?", "Taro"])