rails4×Cocoonで部分テンプレートに変数を渡す際に詰まったのでメモ

## はじめに
エンジニア歴一年未満のひよっこの初投稿記事です。
現在業務ではCMSをいじってます。
拙いコードもあるかと思うのでアドバイスやお叱りはコメントでいただけると幸いです。
_※実際のコードよりも少し簡略化しているものを書いてます。_

## 環境
- Ruby:  2.3.6
- Rails: 4.2.8

## 概要
動的フォームを作るgem : [cocoon](https://github.com/nathanvda/cocoon)を使ってフォームを作っていた際に`locals`でうまく変数が渡せなかったのですが、公式ドキュメントを使って一応解決できたので備忘録代わりに。

## model
以下のように、`post`/`tag`/`category`という3つのモデルがあり、
- `category` - `post` / `category` - `tag`はそれぞれ一対多
- `post`と`tag`は多対多
の関係でつながっています。今回は`post`のform内でpost_tagsを生成する必要があり、cocoonを使いました。

```ruby:post.rb
class Post < ActiveRecord::Base
  belongs_to :category
  has_many :post_tags, dependent: :destroy
  has_many :tags, through: :post_tags
  accepts_nested_attributes_for :post_tags , allow_destroy: true
end
```

```ruby:tag.rb
class Tag < ActiveRecord::Base
  belongs_to :category
  has_many :post_tags, dependent: :destroy
  has_many :posts, through: :post_tags
end
```

```ruby:category.rb
class Category < ActiveRecord::Base
  has_many :posts
  has_many :tags
end
```

## やりたかったこと
上記のアソシエーションを持つため、
**『postと同じcategoryを持つtagしか、post_tagsに登録したくない！！』**
というのが今回やりたかったことです

## エラーとなったform
### view
```html+erb
<%= form_for(@post) do |f| %>
  <!--中略-->
  <div class="form-group">
    <%= f.label :post_tags, 'タグ', class: 'control-label' %>
    <%= link_to_add_association "タグ追加", f, :post_tags, partial: "parts/tag_fields", data: {association_insertion_node: '#tag-box', association_insertion_method: 'append'} %>
      <div id="tag-box">
        <%= f.fields_for :post_tags do |d| %>
          <%= render 'parts/tag_fields', { f: d, tags: @tags }  %>
        <% end %>
      </div>
    </div>
  </div>
  <%= f.submit "保存", class: 'btn btn-primary' %>
<% end %>
```

```html+erb:parts/_tag_fields.html.erb
<div class="nested-fields">
  <%= f.hidden_field :id %>
  <div class="input-group input-group-sm" style="margin-bottom: 5px;">
    <div>
      <%= f.collection_select :tag_id, tags, :id, :name, {}, class: 'form-control input-sm' %>
    </div>
  </div>
</div>
```

### controller
```ruby:posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post_and_tags

  def edit; end

  # 中略

  private

  def set_post_and_tags
    @post = Post.find(params[:post_id])
    @tags = @post.category.tags
  end

end
```

以上を実行すると、`undefined local variable or method 'tags'`となってしまいます。
**「なぜだ！！renderでちゃんとオプション指定しているのに。。」**

## なにが問題だったのか
オプションの記述でいろいろミスってるかな、、と思い試しましたが解決せず。
基本に立ち返って公式ドキュメントを、、、と、調べたらありました。（始めからそうすべきでした）
> render_options : options passed through to the form-builder function (e.g. simple_fields_for, semantic_fields_for or fields_for). If it contains a :locals option containing a hash, that is handed to the partial.

>```
= link_to_add_association 'add something', f, :something,
    render_options: {locals: { sherlock: 'Holmes' }}
```

なるほど、`link_to_add_association`の方にも指定せねばいけないのですね。


## 修正したコード
```html+erb
<%= form_for(@post) do |f| %>
   <!--中略-->
   <div class="form-group">
     <%= f.label :post_tags, 'タグ', class: 'control-label' %>
     <%= link_to_add_association "タグ追加", f, :post_tags, partial: "parts/tag_fields", data: {association_insertion_node: '#tag-box', association_insertion_method: 'append'}, , render_options: {locals: { tags: @tags }} %>
     <div id="tag-box">
       <%= f.fields_for :post_tags do |d| %>
         <%= render 'parts/tag_fields', { f: d, tags: @tags }  %>
       <% end %>
      </div>
    </div>
  </div>
  <%= f.submit "保存", class: 'btn btn-primary' %>
<% end %>
```
少し見辛いですが、
`link_to_add_association`の最後に`render_options: {locals: { tags: @tags }}`を付け加えたら解決しました。

## 参考
- nathanvda/cocoon : https://github.com/nathanvda/cocoon