更新:此答案适用于Rails 2,或者如果您有需要自定义逻辑的特殊约束。如在别处讨论的那样,使用fields_for很好地解决了简单的情况。
Rails并不会为您提供很多帮助。它违反了标准的视图约定,因此您必须在视图,控制器甚至路由中进行变通。没意思
使用Rails方式处理多模型表单的关键资源是Stephen Chu的params-foo系列,或者如果您使用的是Rails 2.3,请查看嵌套对象表单
如果您定义了某种正在编辑的单一资源(例如照片集),它将变得更加容易。Photoset可以是真实的ActiveRecord模型类型,也可以只是接受数据并引发错误的外观,就像是ActiveRecord模型一样。
现在,您可以编写如下所示的视图表单:
<%= form_for :photoset do |f|%>
<% f.object.photos.each do |photo| %>
<%= f.fields_for photo do |photo_form| %>
<%= photo_form.text_field :caption %>
<%= photo_form.label :caption %>
<%= photo_form.file_field :attached %>
<% end %>
<% end %>
<% end %>
您的模型应验证进入的每个子照片并汇总其错误。您可能想查看一篇不错的文章,介绍如何在任何类中包括Validation。它可能看起来像这样:
class Photoset
include ActiveRecord::Validations
attr_accessor :photos
validate :all_photos_okay
def all_photos_okay
photos.each do |photo|
errors.add photo.errors unless photo.valid?
end
end
def save
photos.all?(&:save)
end
def photos=(incoming_data)
incoming_data.each do |incoming|
if incoming.respond_to? :attributes
@photos << incoming unless @photos.include? incoming
else
if incoming[:id]
target = @photos.select { |t| t.id == incoming[:id] }
end
if target
target.attributes = incoming
else
@photos << Photo.new incoming
end
end
end
end
def photos
# your photo-find logic here
@photos || Photo.find :all
end
end
通过为Photoset使用外观模型,您可以使控制器和视图逻辑保持简单明了,并为专用模型保留最复杂的代码。该代码可能不会立即可用,但希望它将为您提供一些想法,并为您指出解决问题的正确方向。