我有一个名为“联系人”的模型,其中有一位客人。
class Contact < ActiveRecord::Base
has_one :guest, :class_name => "Contact", :foreign_key => "guest"
end
在我的创建视图中,我使用select helper方法列出所有可以作为访客选择的联系人,如此...
<% form_for(@contact) do |f| %>
<%= f.error_messages %>
...
<p>
<%= f.label :guest %><br />
<% @guests = Contact.find(:all, :order => "lastname").map { |u| [u.lastname + ', ' + u.firstname, u.id] } %>
<%= f.select :guest, @guests, {:include_blank => true} %>
</p>
...
<% end %>
每当提交此表单时,我都会收到一条错误消息,说它正在等待联系但是有一个字符串。
在将当前联系人保存到数据库之前,我应该在何处以及如何将表单提交的字符串转换为联系人?
答案 0 :(得分:6)
在Rails中创建关联时,例如has_one,有一些为对象动态生成的方法,以便于分配。
目前,您使用的方法是
@contact.guest = @guest
并且您的联系对象期望接收可能与其关联的另一个ActiveRecord对象。你想要做的是,在你的形式包装模型对象时,这种方法是“假的”。 (来自params的信息以字符串形式出现,这就是你得到错误的原因)
有几种方法可以实现这一点。第一个是使用嵌套模型属性。 。 。复杂的表单,允许您在您正在使用的form_for
中包装子关联(使用fields_for
表单帮助程序)。对此进行解释需要花费很长时间才能打字,幸运的是,复杂表格上有令人难以置信的免费资源:
Railscasts Complex Forms part 1
Railscasts Complex Forms part 2
Railscasts Complex Forms part 3
此外,如果您使用的是Rails 2.3,请查看有关“accepts_nested_attributes_for
”的一些信息。 。 。现在有一个明显缺乏教程,但我想,随着2.3的发布,将有很多即将到来。这个方便的小助手将削减Ryan在他的屏幕演员中使用的代码的大约一半,以使表单接受一个次级模型。
最后有一个解决方法。如果您的关系很简单,如果要关联的guest虚拟机已经在数据库中,并且您不需要从正在使用的表单中创建新的guest虚拟机,那么您可以使用类似虚拟属性的内容。在您的表单中,只需将f.select :guest
更改为类似f.select :guest_select
的内容,并在模型中实施方法:
def guest_select=(incoming_id_from_form)
contact = Contact.find(incoming_id_from_form)
self.guest = contact
end
这将分配ActiveRecord模型,而无需为您执行复杂的表单!