rails options_from_collection_for_select

#初めに
[collection_check_boxes](https://qiita.com/sibakenY/items/6079605061e2961c9987)と似た感じで使えるのに

options_from_collectoin_for_selectというヘルパーメソッドがありました。

これは名前からわかるようにselectタグを使うときのメソッドで

例えば既存のタグの名前からセレクトタグを自動的に生成するやつです。

#使い方

まずrails guidesにはoptions_from_collection_for_selectは

> collectionを列挙した結果をoptionタグ化した文字列を返し、呼び出しの結果をvalue_methodにオプション値として割り当て、text_methodにオプションテキストとして割り当てます。

このように書いてありました。

例のごとく一回読んだだけでは理解できません.....

またこんなことも

> 返されるのはoptionだけです。従って、出力結果の外側を適切なHTML selectタグで囲む必要があります。

要は

```erb 
<%= options_from_collection_for_select(:tag_ids, Tag.all, :id, :name) do |tag| %>
.....
<% end %>

```

みたいな使い方をするわけではなくこのoptions_from_collection_for_selectの外側にselectを使うなら


```
<%= select_tag :tag_id ..... %>
```

みたいにしなくちゃいけない

実際の使い方としては

```erb 
<%= select_tag :tag_id,
           options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]),
           {
                       prompt: 'タグで絞り込み',
                       class: 'form-control select_css_tag',
           }
%>
```

みたいな感じ


#実際に使ってみる

```
rails g model article title
rails g model tag name
rails g model article_tags article:references tag:references
rails db:migrate
rails g controller articles
```

routesの設定はresourcesを使用

modelの設定は基本的な多対多の設定をする

controllerは

```ruby:articles_controller.rb 

class ArticlesController < ApplicationController
  def index
    @articles = Article.all 
  end

  def new 
    @article = Article.new 
  end 

  def create 
    article = Article.new(article_params)
    tag = Tag.find(params[:tag_id])
    if article.save 
      article.tags << tag
      redirect_to articles_path 
    else 
      render :new 
    end 
  end 

  private 

  def article_params 
    params.require(:article).permit(:title,:tag_id)
  end   
end

```


まずcreateではarticleを保存してそのあと

```
article.tags << tag
```

でarticle_tagsを作成しています。

viewは

```erb
<%= form_with model: @article, local: true do |f| %>
    <%= f.label :title %>
    <%= f.text_field :title %>

    <%= select_tag :tag_id,
         options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]), 
            {
                prompt: 'タグを選択',
            }
    %>
    <%= f.submit %>
<% end %>

```


こんな感じ

ちなみに複数の値を保存できるようにしたい場合はこんな感じにmultiple: trueを指定してあげればよいです


```erb 

<%= form_with model: @article, local: true do |f| %>
    <%= f.label :title %>
    <%= f.text_field :title %>

    <%= select_tag :tag_id,
         options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]), 
            {
                prompt: 'タグを選択',
                multiple: true
            }
    %>
    <%= f.submit %>
<% end %>

```


これで複数保存できるようになります。


#発見

これを作ってるときに気づいたんですけど

select_tagでmultipleがtrueのときはparams[:tag_id]が配列で来るんですけど

controllerのcreateアクションが

```ruby 

def create 
    @article = Article.new(article_params)
    @tag = Tag.find(params[:tag_id])
    if @article.save 
      @article.tags << @tag
      redirect_to articles_path 
    else 
      render :new 
    end 
  end 
```

このままでも複数個を保存することができました。

binding.pryで調べてみたところ

Tag.find(params[:tag_id])

のところでtag_idが["1", "2"]となっているときに

```ruby 
    10: def create
    11:   @article = Article.new(article_params)
    12:   @tag = Tag.find(params[:tag_id])
    13:   binding.pry
 => 14:   if @article.save
    15:     @article.tags << @tag
    16:     redirect_to articles_path
    17:   else
    18:     render :new
    19:   end
    20: end

[1] pry(#<ArticlesController>)> @tag
=> [#<Tag:0x00007f36182a6d90
  id: 1,
  name: "Ruby",
  created_at: Mon, 11 Feb 2019 06:35:46 UTC +00:00,
  updated_at: Mon, 11 Feb 2019 06:35:46 UTC +00:00,
  article_id: nil>,
 #<Tag:0x00007f36182a6c50
  id: 2,
  name: "Ruby on Rails",
  created_at: Mon, 11 Feb 2019 06:35:58 UTC +00:00,
  updated_at: Mon, 11 Feb 2019 06:35:58 UTC +00:00,
  article_id: nil>]
[2] pry(#<ArticlesController>)>
```

こんな感じでちゃんとすべて取れてるんですよね。

Model.findって一個しか取ってこれないと思っていたので大発見でした。

またこれは基本的なことなのかもしてないですが@tagが配列の時

```ruby
@article.tags << @tag
```

も問題なく動いてくれるんですね

普通ならループ作って

```ruby 
@tag.each do |tag|
  @article.tags << tag 
end 
```

としてしまいます。



おわり:sunny: