【问题标题】:Preventing duplicates via a custom foreign key in has_many :through通过 has_many 中的自定义外键防止重复:通过
【发布时间】:2013-08-01 15:03:15
【问题描述】:

我正在尝试使用 UserLocations 连接表在 User 模型和 Location 模型之间实现双向 has_many :through 关联。这将启用使用内置 ActiveRecord 方法设置用户位置,即。 @user.locations = [<Location 1>, <Location 2>, ...]。我的目标是不将位置与用户单独关联,而是让用户通过另一个字段一次或多个添加和删除它们::zip_code。这意味着当用户添加邮政编码时,ActiveRecord 应该将一条记录插入到 UserLocations(类似于INSERT INTO user_locations (user_id, zip_code) VALUES (1, 12345))。然后,当调用@user.locations 时,ActiveRecord 应该通过:zip_code 加入并获取匹配的位置。我当前的实现有效,除了为与邮政编码关联的每个位置生成一个 INSERT 到 UserLocations。

class User < ActiveRecord::Base
  has_many :user_locations
  has_many :locations, through: :user_locations
end

class UserLocation < ActiveRecord::Base
  belongs_to :user
  belongs_to :location, primary_key: :zip_code, foreign_key: :zip_code
end

class Location < ActiveRecord::Base
  has_many :user_locations, primary_key: :zip_code, foreign_key: :zip_code
  has_many :users, through: :user_locations
end

我尝试过的事情:

  • validates_uniqueness_of :zip_code, scope: :user_id - 只是抛出一个验证错误并阻止所有记录创建
  • has_many unique: true - 不会阻止重复的数据库查询
  • add_index unique: true for (user_id, zip_code) - 至少可以防止创建重复条目,但我正在尝试完全防止不必要的查询

使用this one 之类的问题寻求指导并没有让我更接近。如果不使用我自己的方法来获取/设置用户位置,我正在尝试做的事情是否可行?

【问题讨论】:

  • 乔希,如果下面的答案之一对您有帮助,您需要接受它

标签: mysql ruby-on-rails associations has-many-through


【解决方案1】:

首先,我在 Rails 方面还不是很有经验,但我仍然会尽力提供帮助 :)

我不会使用邮政编码作为密钥。当用户输入邮政编码时,您在 Location 中查找该编码:

@zip_code = Location.where(zipcode: user_input).first
@zip_code.user_locations.create!(user_id #some other stuff you want)

通过这种方式,您可以将位置的 id 存储到用户位置中,并且不会重复。然后,您可以通过加入 UserLocation 和 Location 来生成用户位置。

但正如我所说,作为初学者,可能有更好的方法。

【讨论】:

  • 我认为你基本上是在建议将用户直接关联到位置,所以连接表有 user_id, location_id 可以防止重复并使 @user.locations 可用等。这并没有实现我添加的目标/removing zips 单查询操作(因为一个邮政编码可以有多个位置)。我的应用程序旨在允许其中许多操作快速执行(即它们需要便宜),而位置查找可能相对昂贵。我误解了你的建议吗?
【解决方案2】:

如果我错了就阻止我:)

您的locations 表中有邮政编码(即:111、222、333) 当用户为自己选择邮政编码“111”时,他的记录与现有的locations 记录相关联;但是当用户选择邮政编码“444”时,会创建一个新的locations 记录并链接到该用户。选择“444”的下一次使用将链接到同一条记录。

如果我的假设是正确的,你应该有:

  • validates_uniqueness_of :zip_code(无范围)在您的 Location 模型中
  • 在您的User 模型中创建/更新您可以使用Location.find_or_create_by(params[:zipcode])

这是伪代码(不要复制粘贴),我不知道你的代码是怎么写的,但我的意思是让你看看find_or_create,我相信它可能是你的解决方案

【讨论】:

    【解决方案3】:

    您的关联设置似乎正确。

    当您在 rails 中有 has_many 关联并想要执行以下操作时:

    @user.locations = [<Location 1>, <Location 2>, ...]
    

    Rails 将为数组中的每个位置创建单独的 INSERT 语句,尽管它会为您执行大量 DELETE。如果您希望它执行批量 INSERT 语句,则需要滚动您自己的代码或查看 activerecord-import gem 来执行此操作。

    至于重复,如果您只执行上述代码,则不应出现重复记录错误,除非该位置数组中有重复,在这种情况下您应先调用uniq

    【讨论】:

      猜你喜欢
      • 2013-04-19
      • 2011-02-22
      • 1970-01-01
      • 1970-01-01
      • 2011-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多