楽したいんですよ、綺麗にコードかけるし、書かなくていいかもしれないですし
昨日はもう出歩きたくないようなひどい雨風でしたが、今日は打って変わっていい天気です。涼しくなってきて夏も終わりが近いと感じます。
さて、今回は「多対多の関連を持つデータをRailsでうまく保存したく」なりました。
データを表示する段階の問題
newやeditで毎回
@hoges = Hoge.all @piyos = Piyo.all
みたいなことをやっていました。これはこれでまあ悪くはないのですが、いちいちこれを書くのは面倒ですし、createやupdateでエラーが起きたらリダイレクト→入力したデータが消える\(^o^)/というユーザービリティが悪い状態でした。これはいけないなと思い、他の人が書いたコード参考に…
# この書き方をするには「multipluck」というgemが必要です。 def hoge_options Hoge.pluck [:name, :id] end def piyo_options Piyo.pluck [:name, :id] end
というコードをヘルパーに書いて*1、ビューの方で
<%= f.select :hoge_id, options_for(hoge_options) %> <% piyo_options.each |piyo| %> <%= f.check_box :piyo_id, piyo.last %><label><%= piyo.first %></label> <% end %>
みたいに書けばすっきりするという結論に至りました。
保存するところでの問題
願わくば何も考えずに
User.create(params)
とかやりたいのですが、果たしてできるのでしょうか。調べてみると、accepts_nested_attributes_for
を使って設定すればいいらしいことが分かりました。
モデル側に、
class User < ActiveRecord::Base attr_accessible :hoges, :user_hoges, :hoge_attributes has_many :user_hoges has_many :hoges, :through => :user_hoges accepts_nested_attributes_for :user_hoges end
ビュー側に、
<%= f.fields_for :user_hoges |h| %> <%= h.hidden_field :user_id, @user.id %> <%= h.select :hoge_id, options_for(hoge_options), {}, :multiple => true %> <% end %>
とか書いておけばOKです。多対多の場合、中間モデルをfields_forで指定するのがポイントです。
*1:multipluckを使わなくても[:name, :id].map{|s| Hoge.pluck s }.transposeでいけます