はじめに
この記事はTwitterで人気のハッシュタグ#100DaysOfCode
をつけて、
100日間プログラミング学習を続けるチャレンジに挑戦した7日目の記録です。
動作環境
- ruby 2.4.1
- Rails 5.0.1
現在学習している内容のリポジトリ
本日学んだこと
- accepts_nested_attributes_forによるCRUD操作
accepts_nested_attributes_for
については以下の記事で解説しています。
accepts_nested_attributes_forについて学ぶ_100DaysOfCodeチャレンジ6日目(Day_6:#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
}
]
}
参考リンク