【问题标题】:Rails unique column has duplicatesRails 唯一列有重复项
【发布时间】:2012-08-13 08:59:12
【问题描述】:

这是我的模型的精简版。

model Paper
  PAPER_STARTING_NUMBER = 1

  validate_uniqueness_of :number, :allow_blank => true
  before_create :alocate_paper_number

  def alocate_paper_number
    return true if self.number.present?
    p_number = Paper.maximum('number') || Paper::PAPER_STARTING_NUMBER 
    self.number = p_number >= Paper::PAPER_STARTING_NUMBER ? p_number+1 : Paper::PAPER_STARTING_NUMBER 
    return true 
  end
end

问题是我在数字列中有重复项。 任何想法为什么以及如何在不更改回调的情况下解决此问题。 我知道我可以在数据库上添加唯一性验证或对该列进行序列化,还有其他想法吗?

【问题讨论】:

    标签: ruby-on-rails ruby validation postgresql


    【解决方案1】:

    首先你要了解回调的顺序:

    (-) 保存

    (-) 有效

    (1) before_validation

    (-) 验证

    (2) after_validation

    (3) before_save

    (4) before_create

    (-) 创建

    (5) after_create

    (6) after_save

    (7) after_commit

    如您所见,它验证了您的 number 属性的唯一性,然后 before_create 可以自行处理您的验证想要完成的事情。

    关于更简洁的架构,我会将这两个想法放在您的自定义模型中,因为用户似乎无法选择数字。这只是一个增量器,对吧?

    def alocate_paper_number
      p_number = Paper.maximum('number') || Paper::PAPER_STARTING_NUMBER 
      self.number = p_number + 1
    end
    

    单独的 sn-p 可以防止重复,因为它总是向上递增(除非,数字可能会以我不知道的其他方式发生),而且没有理由返回所有这些 true .说的很对!

    【讨论】:

    • 如果你有` p_number = Paper.maximum('number') || Paper::PAPER_STARTING_NUMBER ` 和 self.number = p_number + 1 然后确保您有 PAPER_STARTING_NUMBER = 0 以从 1 开始计数。
    • 没有其他修改number属性的方法。如果我尝试同时添加 2 篇论文,它会给我重复的数字。
    • "在 de docs.validate_uniqueness_of 试图使它唯一。但是如果两个进程同时添加一个记录,它们都可以包含相同的数字。" Hugo Logmans 似乎是对的。
    • “单独的 sn-p 可以防止重复”不,一点也不。如果同时保存两个对象,它们的alocate_paper_number 和 INSERT 可以交错并且您得到重复,那么这里有一个简单的竞争条件。您必须在数据库中使用唯一约束并准备好处理约束违规。或者更好的是,让数据库处理这个逻辑(尽管 Rails 认为数据库中不应该有任何逻辑的奇怪和错误的想法)。
    • 好的,所以我在数据库上添加了唯一性约束,并在控制器上添加了一个救援块,因此如果数据库抛出 RecordNotUnique 异常,我将发送 create 方法。感谢您的所有帮助。
    【解决方案2】:

    它在 de docs 中。 validate_uniqueness_of 尝试使其独一无二。但是如果两个进程同时添加一条记录,它们都可以包含相同的数字。

    如果你想保证唯一性,就让数据库来做吧。但是因为每个 DB 不同,Rails 在设计上并不支持它。

    这里有解释:http://guides.rubyonrails.org/active_record_validations_callbacks.html#uniqueness

    使用解决方案:“为避免这种情况,您必须在数据库中创建唯一索引。”

    【讨论】:

      【解决方案3】:

      我如何修复它(请记住我无法返回验证错误) 我在数字列上添加了唯一性索引(如 mu 和 Hugo 建议的那样) 并且因为我无法在控制器中返回验证错误

      class PaperController < ApplicationController
        def create
          begin
            @paper.save
          rescue ActiveRecord::RecordNotUnique
            @paper.number = nil
            create
          end
        end
      end
      

      【讨论】:

      • 啊,就是这样。做得好!我很好奇@Mu 对此有何看法。
      猜你喜欢
      • 2018-01-21
      • 1970-01-01
      • 2010-11-26
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      • 2013-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多