はじめに
この記事はTwitterで人気のハッシュタグ#100DaysOfCode
をつけて、
100日間プログラミング学習を続けるチャレンジに挑戦した3日目の記録です。
動作環境
- ruby 2.4.1
- Rails 5.0.1
現在学習している内容のリポジトリ
本日学んだこと
- モデル同士の関連付け(belongs_to)
- belogns_toのオプションについて
関連付けについて
ContactモデルとKindモデルがあったとします。
Contactテーブルにあるkind_idは外部キーとなっており、Kindテーブルのidを参照している状態。
そのため、Contactモデルが、以下のように定義されているとき、kind_idを指定しないとAPIなどでPOSTした際にエラーとなる。
# app/models/contact.rb
class Contact < ApplicationRecord
belongs_to :kind
end
Postmanでkind_idを指定せずにPOSTすると、エラーとなり失敗してしまいます。。
コンソールで確認してみても、Rollbackが発生しているのが確認できますね。
belongs_toのオプション
先ほどはkind_idを指定しないとエラーになると説明しましたが、実はoptional:
をtrue
にすればnullになるだけでエラーにはなりません。
PostmanでAPIに対してPOSTしてみると、kind_idはnullですがちゃんとリクエストが送れていますね。
コンソールでもちゃんとcommitされているのがわかります。
Started POST "/contacts" for 127.0.0.1 at 2018-06-19 01:16:44 +0900
Processing by ContactsController#create as */*
Parameters: {"name"=>"Yuta-Ushijima", "email"=>"sample@test.com", "contact"=>{"name"=>"Yuta-Ushijima", "email"=>"sample@test.com"}}
(0.1ms) begin transaction
SQL (3.4ms) INSERT INTO "contacts" ("name", "email", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "Yuta-Ushijima"], ["email", "sample@test.com"], ["created_at", "2018-06-18 16:16:45.343412"], ["updated_at", "2018-06-18 16:16:45.343412"]]
(5.5ms) commit transaction
Completed 201 Created in 152ms (Views: 14.7ms | ActiveRecord: 26.0ms)
関連付けをしたらstrong_paramsの設定を忘れずに
それではここで、kind_idを指定して改めてPOSTしてみます。
おや、しっかりとkind_idを指定しているのに、kind: must exist
となっていますね。
なぜでしょうか。
実はこれ、strong_paramsの設定において、kind_idのパラメータが送られてくることを許可していないことが原因なのです。
コンソールで確認してみると、Unpermitted parameter: kind_id
となっています。
Started POST "/contacts" for 127.0.0.1 at 2018-06-19 01:20:26 +0900
Processing by ContactsController#create as */*
Parameters: {"name"=>"Yuta-Ushijima", "email"=>"sample@test.com", "kind_id"=>2, "contact"=>{"name"=>"Yuta-Ushijima", "email"=>"sample@test.com", "kind_id"=>2}}
Unpermitted parameter: kind_id
(0.3ms) begin transaction
(0.1ms) rollback transaction
Completed 422 Unprocessable Entity in 93ms (Views: 0.9ms | ActiveRecord: 20.1ms)
この問題を解消するには、strong_paramsの設定をしているcontacts_controller.rb
を変更してあげればOK。
現在の設定
class ContactsController < ApplicationController
## 中略
private
# Only allow a trusted parameter "white list" through.
def contact_params
params.require(:contact).permit(:name, :email, :birthdate)
end
end
permitの引数にシンボルで:name, :email, :birthday
を渡していますね。
ここの箇所に:kind_id
のように渡してあげれば、問題なくPOSTできるようになるはずです。
変更後
class ContactsController < ApplicationController
## 中略
private
# Only allow a trusted parameter "white list" through.
def contact_params
params.require(:contact).permit(:name, :email, :birthdate, :kind_id)
end
end
コンソールでもきちんとcommitされているのがわかります。
Started POST "/contacts" for 127.0.0.1 at 2018-06-19 01:34:04 +0900
Processing by ContactsController#create as */*
Parameters: {"name"=>"Yuta-Ushijima", "email"=>"sample@test.com", "kind_id"=>2, "contact"=>{"name"=>"Yuta-Ushijima", "email"=>"sample@test.com", "kind_id"=>2}}
(0.1ms) begin transaction
Kind Load (7.3ms) SELECT "kinds".* FROM "kinds" WHERE "kinds"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
SQL (4.6ms) INSERT INTO "contacts" ("name", "email", "created_at", "updated_at", "kind_id") VALUES (?, ?, ?, ?, ?) [["name", "Yuta-Ushijima"], ["email", "sample@test.com"], ["created_at", "2018-06-18 16:34:05.078798"], ["updated_at", "2018-06-18 16:34:05.078798"], ["kind_id", 2]]
(6.5ms) commit transaction
Completed 201 Created in 142ms (Views: 3.5ms | ActiveRecord: 30.4ms)