1回すべてのつまづきポイントにつまづけば次からは楽な気がするが...
今回のを試すために書いた全ソース
Release refactoring form · shingo-nakanishi/workout_rails
つまづきポイント1
入れ子を条件によってはINSERTしたくない場合どうしたらよいかわからない。
答え:
reject_ifオプションを使う
つまづきポイント2
そもそも入れ子のformの書き方がわからない。
答え:
class PostsController < ApplicationController
def new
@post = Post.new
@post.post_categories.build
end
def create
@post = Post.new(create_params)
@post.save!
rescue ActiveRecord::RecordInvalid
puts "ERROR"
end
def edit
@post = Post.find(params[:id])
unless @post.post_categories.present?
@post.post_categories.build
end
end
def update
@post = Post.find(params[:id])
ActiveRecord::Base.transaction do
@post.update!(update_params)
end
rescue ActiveRecord::RecordInvalid
puts "ERROR"
end
private
def create_params
params.require(:post).permit(:description, post_categories_attributes: [:post_category_id])
end
def update_params
params.require(:post).permit(:description, post_categories_attributes: [:id, :post_category_id])
end
end
<%= form_for @post do |f| %>
<%= f.label :description %><%= f.text_field :description %><br/>
<%= f.fields_for :post_categories do |b| %>
<%= b.label :post_category_id %>
<%= b.collection_select :post_category_id,
PostCategoryMaster.all,
:id,
:name,
multiple: true,
prompt: 'please select' %>
<% end -%>
<%= f.submit %>
<% end %>
参考
いまさら聞けない!? accepts_nested_attributes_forの使い方 - (゚∀゚)o彡 sasata299's blog
つまづきポイント3
Editで入れ子のデータが選ばれなくなったときはDELETEする方法がわからない。
答え:
allow_destroyを使う
class Post < ActiveRecord::Base
has_many :post_categories, inverse_of: :post
accepts_nested_attributes_for :post_categories,
allow_destroy: true,
reject_if: :is_reject
private
def is_reject(attributes)
is_exist = attributes[:id].present?
is_empty = attributes[:post_category_id].blank?
attributes.merge!(_destroy: 1) if is_exist and is_empty
!is_exist and is_empty
end
end
参考
ruby on rails - Destroy on blank nested attribute - Stack Overflow
削除系についてもっと
【Rails】fields_for と accepts_nested_attributes_for - kzy52's blog
ビューから _destroy を渡せない場合は
mark_for_destruction
を使う
つまづきポイント4
Has-Many-Through Relationsは一手間加えないとうまくいかない。
答え:
inverse_ofを使う
ふつうの has_manyなときは使う必要ないはず。
参考
accepts_nested_attributes_for with Has-Many-Through Relations
つまづきポイント5
has_manyなやつcountすると思ったのと違う値が返ってくる
オブジェクトを保持している数を表すlengthは2だけど、DB上の数を表すcountは1になっているということ。
参考
accepts_nested_attributes_forの:allow_destroyオプション - akimatter
つまづきポイント6
UPDATEするときは要件に合わせてメソッドを選ぶ(accepts_nested_attributes_forと関係なくそうだが)