1 つのフォームで複数のモデルオブジェクトを使う
1 つのフォームで複数のモデルオブジェクトを使いたい場合、Merb では「text_field :mail」のようには書けず、「text_field :name=>"user[#{user.id}][mail]"」のように手動で name 属性を指定しないといけない。
たとえば:
<% @users.each do |user| %> <% id = user.id %> <p> <%= text_field :name => "user[#{user.id}][name]", :label => 'Name', :value => user.name, :id => "user_name_#{user.id}", %> <%= text_field :name => "user[#{id}][mail]", :label => 'Mail', :value => user.mail, :id => "user_mail_#{user.id}" %> </p> <% end %>
とすると:
<p> <label for="user_name_101">Name</label> <input type="text" name="user[101][name]" id="user_name_101" value="Foo" /> <label for="user_mail_101">Mail</label> <input type="text" name="user[101][mail]" id="user_mail_101" value="foo@mail.com" /> </p> <p> <label for="user_name_102">Name</label> <input type="text" name="user[102][name]" id="user_name_102" value="Bar" /> <label for="user_mail_102">Mail</label> <input type="text" name="user[102][mail]" id="user_mail_102" value="bar@mail.com" /> </p>
が生成される。こうすると、コントローラ側では:
def update p params[:user] #=> {"101"=>{"name"=>"Foo", "mail"=>"foo@mail.com"}, # "102"=>{"name"=>"Bar", "mail"=>"bar@mail.com"}} params[:user].each do |user_id, values| user = User.get(user_id) or raise NotFound user.update_attributes(values) ... end end
のように書ける。
しか〜し、手動で name 属性や id 属性を指定するのはいけてない。
そこで、merb-helpers を拡張してみた。これを「require 'merb-helpers-monkey'」とかして読み込むと:
<% @users.each do |user| %> <%= fields_for user, :index_by => :id do %> <p> <%= text_field :name, :label => 'Name' %> <%= text_field :mail, :label => 'Mail' %> </p> <% end =%> <% end %>
のように書ける。ステキ!
ポイントは、fields_for につけた「:index_by => :id」ね。分かってるとは思うけど。