Edited at

accepts_nested_attributes_forによるCRUD操作について学ぶ_100DaysOfCodeチャレンジ7日目(Day_7:#100DaysOfCode)

More than 1 year has passed since last update.


はじめに

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

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


動作環境


  • ruby 2.4.1

  • Rails 5.0.1


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

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


本日学んだこと


  • accepts_nested_attributes_forによるCRUD操作

accepts_nested_attributes_forについては以下の記事で解説しています。

accepts_nested_attributes_forについて学ぶ100DaysOfCodeチャレンジ6日目(Day6:#100DaysOfCode)


CRUD(クラッド)とは?

CRUDとは、以下の頭文字を組み合わせて作成された用語です。


  • Create(登録)

  • Read(参照)

  • Update(更新)

  • Destroy(削除)

CRUDはシステムを構築する上で重要な4つのメイン機能を、一つの言葉として表しているんですね。

乱暴な言い方をすれば、CRUD操作ができれば、最低限システムとして成り立っていることになります。


accepts_nested_attributes_forでCRUD操作をやってみる

accepts_nested_attributes_forメソッドを使ってCRUD操作を行う時、いくつかポイントがあるのでみて行きましょう。


Create(Strong_paramaters)

Strong_paramatersは、Rails4系から搭載されたActiveRecordの機能。

requireメソッドでモデル名、permitメソッドでモデルが持つ属性名を指定することで、その指定条件にマッチしたパラメーターだけを受け付けるというものです。

accepts_nested_attributes_forでCreateをする場合、Strong_paramatersで対象となるモデルの属性名を指定する必要があります。

#{関連したモデル名}_attributes: [:属性名]の形式でpermitメソッドの引数に渡してあげればCreateできるようになりますね。


Contactモデル

# app/models/contact.rb

class Contact < ApplicationRecord
# モデル同士の関連付け
belongs_to :kind
has_many :phones

accepts_nested_attributes_for :phones
end


Phoneモデル

class Phone < ApplicationRecord

belongs_to :contact, optional: true
end


contactコントローラー


# POST /contacts
def create
@contact = Contact.new(contact_params)

if @contact.save
render json: @contact, status: :created, location: @contact
else
render json: @contact.errors, status: :unprocessable_entity
end
end

private

def contact_params
params.require(:contact).permit(:name, :email,
:birthdate, :kind_id,
phones_attributes: [:number])
end


Read(include)

accepts_nested_attributes_forのRead操作は、対象となるアクションにincludeメソッドを使ってモデル名をシンボルで渡してあげればOK。


contactコントローラー

# GET /contacts/1

def show
render json: @contact, include: [:kind, :phones]
end

renderによってJSONでの表示結果が、KindモデルとPhoneモデルもネストされた状態で出力されるようになります。

# render jsonによる出力結果

{
"id": 4,
"name": "菅原 拓海",
"email": "providenci@swaniawski.co",
"birthdate": "2012-06-03",
"created_at": "2018-06-20T14:02:48.716Z",
"updated_at": "2018-06-20T14:02:48.716Z",
"kind_id": 1,
"kind": {
"id": 1,
"description": "Goodmorning!",
"created_at": "2018-06-20T14:02:47.349Z",
"updated_at": "2018-06-20T14:02:47.349Z"
},
"phones": [
{
"id": 6,
"number": "080-8807-5906",
"contact_id": 4,
"created_at": "2018-06-20T14:02:49.660Z",
"updated_at": "2018-06-20T14:02:49.670Z"
},
{
"id": 7,
"number": "080-6345-8352",
"contact_id": 4,
"created_at": "2018-06-20T14:02:49.678Z",
"updated_at": "2018-06-20T14:02:49.684Z"
},
{
"id": 8,
"number": "090-5822-0671",
"contact_id": 4,
"created_at": "2018-06-20T14:02:49.691Z",
"updated_at": "2018-06-20T14:02:49.698Z"
},
{
"id": 225,
"number": "070-1407-9142",
"contact_id": 4,
"created_at": "2018-06-20T14:46:42.691Z",
"updated_at": "2018-06-20T14:46:42.691Z"
}
]
}


Update(id)

accepts_nested_attributes_forのUpdate操作は、対象となるIDを指定する必要があります。


Contactモデル

# app/models/contact.rb

class Contact < ApplicationRecord
# モデル同士の関連付け
belongs_to :kind
has_many :phones

accepts_nested_attributes_for :phones
end

この場合、Phoneモデルの情報を更新させたい場合には、contact_idに紐づいたPhoneモデルのidを指定する必要があるということになりますね。


Before


{
"id": 4,
"name": "菅原 拓海",
"email": "providenci@swaniawski.co",
"birthdate": "2012-06-03",
"created_at": "2018-06-20T14:02:48.716Z",
"updated_at": "2018-06-20T14:02:48.716Z",
"kind_id": 1,
"kind": {
"id": 1,
"description": "Goodmorning!",
"created_at": "2018-06-20T14:02:47.349Z",
"updated_at": "2018-06-20T14:02:47.349Z"
},
"phones": [
{
"id": 6,
"number": "080-8807-5906",
"contact_id": 4,
"created_at": "2018-06-20T14:02:49.660Z",
"updated_at": "2018-06-20T14:02:49.670Z"
}
]
}

たとえばPhonesのnumberを更新させたい場合、最低限Afterのように記述する必要があります。


After

{

"id": 4,
"name": "菅原 拓海",
"email": "providenci@swaniawski.co",
"birthdate": "2012-06-03",
"created_at": "2018-06-20T14:02:48.716Z",
"updated_at": "2018-06-20T14:02:48.716Z",
"kind_id": 1,
"kind": {
"id": 1,
"description": "Goodmorning!",
"created_at": "2018-06-20T14:02:47.349Z",
"updated_at": "2018-06-20T14:02:47.349Z"
},
"phones": [
{
"id": 6,
"number": "0120-234-5678",
}
]
}


Delete(allow_destroy: true,_destroy)

accepts_nested_attributes_forによるDelete操作は、モデルにallow_destroy: trueを指定するという特殊な方法で行います。

APIでPhoneモデルのレコードを削除する場合、対象となるidを指定した上でハッシュのkeyに_destroy、valueに1またはtrueを記述します。

その後、Strong_Paramatersのpermitメソッドにシンボルで:_destroyを渡すと、削除されるようになります。

{

"id": 4,
"name": "菅原 拓海",
"email": "providenci@swaniawski.co",
"birthdate": "2012-06-03",
"created_at": "2018-06-20T14:02:48.716Z",
"updated_at": "2018-06-20T14:02:48.716Z",
"kind_id": 1,
"kind": {
"id": 1,
"description": "Goodmorning!",
"created_at": "2018-06-20T14:02:47.349Z",
"updated_at": "2018-06-20T14:02:47.349Z"
},
"phones": [
{
"id": 6,
"_destroy": 1
}
]
}


参考リンク

https://apidock.com/rails/v3.2.3/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for