Ruby on rails 更改关联ID(而不是值)的多对一关联

Ruby on rails 更改关联ID(而不是值)的多对一关联,ruby-on-rails,associations,Ruby On Rails,Associations,我有一个用户模型,它属于:位置(即每个用户只能有一个位置,但一个位置可以由多个用户共享)。users表中有一个location\u id列来跟踪此信息 如果用户想要改变他们的位置,我相信Rails关联的默认行为是改变实际的关联;但是,在这种情况下,我希望现有的关联(即现有的位置记录)保持不变,并创建一个新的关联 例如,假设我们有用户Alice、Bob、Charley和Dave,他们都有location\u id==1,对应于芝麻街123号位置。然后,当Dave将其位置更改为芝麻街124号时,lo

我有一个
用户
模型,它
属于:位置
(即每个用户只能有一个位置,但一个位置可以由多个用户共享)。
users
表中有一个
location\u id
列来跟踪此信息

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

例如,假设我们有用户Alice、Bob、Charley和Dave,他们都有
location\u id==1
,对应于芝麻街123号位置。然后,当Dave将其位置更改为芝麻街124号时,
location
1不应受到任何影响或更改,应该使用新信息创建
Location
2,并更新Dave的用户记录,以反映
Location\u id
现在是2而不是1

我想在模型级别(大概是
用户
模型)进行更改,这样,如果任何位置信息发生更改(
用户
接受:位置
的嵌套属性),则
位置
关联将正确更新,而不会覆盖现有信息


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

接受嵌套的属性\u 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\u 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

接受\u嵌套的\u属性\u创建一些用于处理嵌套表单的帮助器方法。在您的情况下,您需要覆盖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\u 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

Location
不仅仅是一个字段(它包含国家、州、城市、地址等),但这是一个有趣的见解-我不知道
Location\u attributes=
方法。我在想,在保存之前,我必须以某种方式更改记录(例如使用
find\u或
),但这可能是一个更好的主意!我能看到的唯一问题是,如果直接访问/更改user.location.attribute,该怎么办?有什么方法可以保护它吗?
Location
不仅仅是一个字段(它有国家、州、城市、地址等),但这是一个有趣的见解-我不知道
Location\u attributes=
方法。我在想,在保存之前,我必须以某种方式更改记录(例如使用
find\u或
),但这可能是一个更好的主意!我能看到的唯一问题是,如果直接访问/更改user.location.attribute,该怎么办?有什么办法保护它吗?