Edited at

belongs_toについて学ぶ_100DaysOfCodeチャレンジ3日目(Day_3:#100DaysOfCode)

More than 1 year has passed since last update.


はじめに

この記事はTwitterで人気のハッシュタグ#100DaysOfCodeをつけて、

100日間プログラミング学習を続けるチャレンジに挑戦した3日目の記録です。


動作環境


  • ruby 2.4.1

  • Rails 5.0.1


現在学習している内容のリポジトリ

https://github.com/yuta-ushijima/notebook-api-on-rails


本日学んだこと


  • モデル同士の関連付け(belongs_to)

  • belogns_toのオプションについて


関連付けについて

ContactモデルとKindモデルがあったとします。

contact-kind-relation.png

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すると、エラーとなり失敗してしまいます。。

contact-kind-relation-postman.png

コンソールで確認してみても、Rollbackが発生しているのが確認できますね。

contact-kind-relation-console.png


belongs_toのオプション

先ほどはkind_idを指定しないとエラーになると説明しましたが、実はoptional:trueにすればnullになるだけでエラーにはなりません。

PostmanでAPIに対してPOSTしてみると、kind_idはnullですがちゃんとリクエストが送れていますね。

contact-kind-relation-postman2.png

コンソールでもちゃんと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してみます。

contact-kind-relation-postman3.png

おや、しっかりと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)