多对一关联,其中关联ID(而不是值)被更改

时间:2011-11-29 17:20:34

标签: ruby-on-rails associations

我有一个User模型belongs_to :location(即每个用户只能有一个位置,但多个用户可以共享一个位置)。 users表格有一个location_id列来跟踪此内容。

但是,如果用户想要更改其位置,我相信Rails关联的默认行为是更改实际关联;但是,在这种情况下,我希望现有的关联(即现有的Location记录)保持不变,并且要创建一个新关联。

例如,假设我们有用户Alice,Bob,Charley和Dave,所有人都有location_id == 1,对应地点123 Sesame St.然后当Dave将他的位置改为124 Sesame St.时,{不应以任何方式影响或更改{1}} 1,并且应使用新信息创建Location 2,并更新Dave的用户记录以反映Location现在是2而不是1。

我想在模型级别进行更改(可能是location_id模型),这样如果任何位置信息发生更改(UserUser),{{1正确更新关联,而不覆盖现有信息。

有没有办法做到这一点,内置到Rails或插件?

1 个答案:

答案 0 :(得分:1)

accepts_nested_attributes_for创建了一些辅助方法来处理嵌套表单。在您的情况下,您将要覆盖setter。这应该可以帮到你。

class User

  accepts_nested_attributes_for :location

  def location_attributes= attrs
    new_location   = Location.where(attrs).first
    new_location ||= Location.create attrs

    self.location = new_location
  end

end

在你的表格中有类似的东西

= f.fields_for :location do |lf|
  .field
    = lf.label      :address
    = lf.text_field :address
  .field
    = lf.label      :city
    = lf.text_field :city

一些注意事项:

  • 如果您的用户根本没有位置,则该位置的字段将不会显示。在表单或控制器中添加对@user.build_location的调用。
  • 您可能想要改进查找/创建逻辑,这是一个非常人为的例子

如果您的位置模型是单个字段,则可以使用虚拟属性

简化整个过程
class User
  def location_address= address
    new_location = Location.find_or_create_by_address(address)
    self.location = new_location
  end

  def location_address
    location.address
  end
end

在这种情况下,您只需要表单中的文本字段

= f.text_field :location_address