通过has_many:through中的自定义外键防止重复

时间:2013-07-31 21:32:35

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

我正在尝试使用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
  • (user_id, zip_code) - 至少会阻止创建重复的条目,但我试图完全阻止不必要的查询

使用像this one这样的问题作为指导并没有让我更接近。如果不使用我自己的方法获取/设置用户位置,我正在尝试做什么?

3 个答案:

答案 0 :(得分:0)

首先,我还没有很好的铁杆经验,但我仍然会尝试帮助:)

我要做的是不使用zipcodes作为密钥。当用户输入邮政编码时,您可以在位置中查找代码:

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

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

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

答案 1 :(得分:0)

如果我错了,请阻止我:)

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

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

    您的validates_uniqueness_of :zip_code型号中的
  • Location(无范围) 创建/更新时{i>模型中的
  • 可以使用User

这是伪代码(不要复制粘贴它),我不知道你的代码是如何写的,但我的观点是你看看Location.find_or_create_by(params[:zipcode]),我相信它可能是你的解决方案

答案 2 :(得分:0)

看起来您正确设置了关联。

如果您在rails中有has_many关联,并希望执行以下操作:

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

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

对于重复项,如果您只是执行上述代码,则除非该位置数组中存在重复项,否则不应存在重复的记录错误,在这种情况下,您应首先在其上调用uniq。 / p>