如何在 Ruby on Rails 中验证一对 id 的唯一性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/923796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:17:54  来源:igfitidea点击:

How do you validate uniqueness of a pair of ids in Ruby on Rails?

ruby-on-railsvalidationmodelunique-constraint

提问by dfrankow

Suppose the following DB migration in Ruby:

假设在 Ruby 中进行以下数据库迁移:

    create_table :question_votes do |t|
      t.integer :user_id
      t.integer :question_id
      t.integer :vote

      t.timestamps
    end

Suppose further that I wish the rows in the DB contain unique (user_id, question_id) pairs. What is the right dust to put in the model to accomplish that?

进一步假设我希望数据库中的行包含唯一的 (user_id, question_id) 对。在模型中放入什么合适的灰尘来实现这一点?

validates_uniqueness_of :user_id, :question_id
似乎只是让行按用户 id 唯一,按问题 id 唯一,而不是按对唯一。

回答by Demi

validates_uniqueness_of :user_id, :scope => [:question_id]

if you needed to include another column (or more), you can add that to the scope as well. Example:

如果您需要包含另一列(或更多),您也可以将其添加到范围中。例子:

validates_uniqueness_of :user_id, :scope => [:question_id, :some_third_column]

回答by pakeha

If using mysql, you can do it in the database using a unique index. It's something like:

如果使用 mysql,您可以使用唯一索引在数据库中执行此操作。它是这样的:

add_index :question_votes, [:question_id, :user_id], :unique => true

This is going to raise an exception when you try to save a doubled-up combination of question_id/user_id, so you'll have to experiment and figure out which exception to catch and handle.

当您尝试保存 question_id/user_id 的双倍组合时,这将引发异常,因此您必须进行试验并找出要捕获和处理的异常。

回答by Jonathan Lin

From RailsGuides. validatesworks too:

来自RailsGuidesvalidates也有效:

class QuestionVote < ActiveRecord::Base
  validates :user_id, :uniqueness => { :scope => :question_id }
end

回答by dpedoneze

The best way is to use both, since rails isn't 100% reliable when uniqueness validation come thru.

最好的方法是同时使用两者,因为当唯一性验证通过时,rails 不是 100% 可靠的。

You can use:

您可以使用:

  validates :user_id, uniqueness: { scope: :question_id }

and to be 100% on the safe side, add this validation on your db (MySQL ex)

并且为了 100% 的安全,在你的数据库(MySQL ex)上添加这个验证

  add_index :question_votes, [:user_id, :question_id], unique: true

and then you can handle in your controller using:

然后您可以使用以下方法处理您的控制器:

  rescue ActiveRecord::RecordNotUnique

So now you are 100% secure that you won't have a duplicated value :)

所以现在你 100% 安全,你不会有重复的值:)

回答by eggdrop

Except for writing your own validate method, the best you could do with validates_uniqueness_ofis this:

除了编写自己的验证方法外,您可以做的最好的事情validates_uniqueness_of是:

validates_uniqueness_of :user_id, :scope => "question_id"

This will check that the user_id is unique within all rows with the same question_id as the record you are attempting to insert.

这将检查 user_id 在与您尝试插入的记录具有相同 question_id 的所有行中是否唯一。

But that's not what you want.

但这不是你想要的

I believe you're looking for the combination of :user_idand :question_idto be unique across the database.

我相信你正在寻找的组合:user_id,并:question_id为整个数据库是唯一的。

In that case you need to do two things:

在这种情况下,您需要做两件事:

  1. Write your own validate method.
  2. Create a constraint in the database because there's still a chance that your app will process two records at the same time.
  1. 编写您自己的验证方法。
  2. 在数据库中创建约束,因为您的应用仍有可能同时处理两条记录。

回答by Francisco Balam

When you are creating a new record, that doesn't work because the idof your parent model doesn't exist still at moment of validations.

This should to work for you.

当您创建新记录时,这不起作用,因为在验证id时您的父模型仍然不存在。

这应该对你有用。

class B < ActiveRecord::Base
  has_many :ab
  has_many :a, :through => :ab
end

class AB < ActiveRecord::Base
  belongs_to :b
  belongs_to :a
end

class A < ActiveRecord::Base
  has_many :ab
  has_many :b, :through => :ab

  after_validation :validate_uniqueness_b

  private
  def validate_uniqueness_b
    b_ids = ab.map(&:b_id)
    unless b_ids.uniq.length.eql? b_ids.length
      errors.add(:db, message: "no repeat b's")
    end
  end
end

In the above code I get all b_idof collection of parameters, then compare if the length between the unique values and obtained b_id are equals.
If are equals means that there are not repeat b_id.

在上面的代码中,我得到了所有b_id参数的集合,然后比较唯一值和获得的 b_id 之间的长度是否相等。
If are equals 表示没有重复b_id

Note: don't forget to add unique in your database's columns.

注意:不要忘记在数据库的列中添加 unique