複数のタイプのモデルを更新するフォーム

form_for ってモデルを一つしか指定できないんだけど、複数のモデルの情報を更新したいときってどうするんだろ。fields_for ってないのかな、なかったら作ろうかな、とか思ってソース見てたら、何のひねりもなく名前まで想像通りのがあった。

# actionpack-2.2.2/lib/action_view/helpers/form_helper.rb
def fields_for(record_or_name_or_array, *args, &block)
  raise ArgumentError, "Missing block" unless block_given?
  options = args.extract_options!

  case record_or_name_or_array
  when String, Symbol
    object_name = record_or_name_or_array
    object = args.first
  else
    object = record_or_name_or_array
    object_name = ActionController::RecordIdentifier.singular_class_name(object)
  end 

  builder = options[:builder] || ActionView::Base.default_form_builder
  yield builder.new(object_name, object, self, options, block)
end 

ってことでこれ使えば複数モデル用のフォームも簡単すね。

<%= form_for @foo_model do |foo_form| %>
  <%= fields_for @bar_model do |bar_fields| %>
    <%= foo_form.error_messages %>
    <%= bar_fields.error_messages %>

    <%= foo_form.text_field :name %>
    <%= bar_fields.text_field :name %>
    <%= foo_form.submit %>
  <% end %>
<% end %>

ってすれば

<form method="post" id="new_foo" class="new_foo" action="/foos">
  <input type="text" name="foo[name]" id="foo_name"/>
  <input type="text" name="bar[name]" id="bar_name"/>
  <input type="submit"/>
</form>

みたいのが生成される。まぁこのままだとエラーメッセージが2枠に分けて出るけど、どうせエラーメッセージなんてRailsのそのままは使わないし。