#初めに
collection_check_boxesと似た感じで使えるのに
options_from_collectoin_for_selectというヘルパーメソッドがありました。
これは名前からわかるようにselectタグを使うときのメソッドで
例えば既存のタグの名前からセレクトタグを自動的に生成するやつです。
#使い方
まずrails guidesにはoptions_from_collection_for_selectは
collectionを列挙した結果をoptionタグ化した文字列を返し、呼び出しの結果をvalue_methodにオプション値として割り当て、text_methodにオプションテキストとして割り当てます。
このように書いてありました。
例のごとく一回読んだだけでは理解できません.....
またこんなことも
返されるのはoptionだけです。従って、出力結果の外側を適切なHTML selectタグで囲む必要があります。
要は
<%= options_from_collection_for_select(:tag_ids, Tag.all, :id, :name) do |tag| %>
.....
<% end %>
みたいな使い方をするわけではなくこのoptions_from_collection_for_selectの外側にselectを使うなら
<%= select_tag :tag_id ..... %>
みたいにしなくちゃいけない
実際の使い方としては
<%= 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は
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は
<%= 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を指定してあげればよいです
<%= 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アクションが
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"]となっているときに
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が配列の時
@article.tags << @tag
も問題なく動いてくれるんですね
普通ならループ作って
@tag.each do |tag|
@article.tags << tag
end
としてしまいます。
おわり