Rails
api
JSON

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

はじめに

この記事は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)