accepts_nested_attributes_for を使った入れ子のformが罠だらけな気がする

1回すべてのつまづきポイントにつまづけば次からは楽な気がするが...

今回のを試すために書いた全ソース
[Release refactoring form · shingo-nakanishi/workout_rails](https://github.com/shingo-nakanishi/workout_rails/releases/tag/v5.0)

## つまづきポイント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](http://blog.livedoor.jp/sasata299/archives/51931176.html)

## つまづきポイント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](http://stackoverflow.com/questions/10943013/destroy-on-blank-nested-attribute/13774269#13774269)

### 削除系についてもっと
[【Rails】fields_for と accepts_nested_attributes_for - kzy52's blog](http://kzy52.com/entry/2013/07/10/200144)

> ビューから _destroy を渡せない場合は `mark_for_destruction` を使う

## つまづきポイント4
Has-Many-Through Relationsは一手間加えないとうまくいかない。

答え：
**inverse_ofを使う**
ふつうの has_manyなときは使う必要ないはず。

### 参考
[accepts_nested_attributes_for with Has-Many-Through Relations](https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through)


## つまづきポイント5
has_manyなやつcountすると思ったのと違う値が返ってくる

>オブジェクトを保持している数を表すlengthは2だけど、DB上の数を表すcountは1になっているということ。

### 参考
[accepts_nested_attributes_forの:allow_destroyオプション - akimatter](http://d.hatena.ne.jp/akm/20090714/1247557847)

## つまづきポイント6
UPDATEするときは要件に合わせてメソッドを選ぶ（accepts_nested_attributes_forと関係なくそうだが）

### 参考
[Different Ways to Set Attributes in ActiveRecord (Rails 4)](http://www.davidverhasselt.com/set-attributes-in-activerecord/)