1

这是我的模型的精简版。

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

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

4

3 回答 3

2

首先你必须了解回调的顺序:

(-) 节省

(-) 有效的

(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

仅该片段就可以防止重复,因为它总是向上递增(除非,数字可能会以我不知道的其他方式发生),而且没有理由返回所有这些真值。它足够真实!

于 2012-08-13T09:53:04.377 回答
2

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

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

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

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

于 2012-08-13T10:09:41.523 回答
1

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

class PaperController < ApplicationController
  def create
    begin
      @paper.save
    rescue ActiveRecord::RecordNotUnique
      @paper.number = nil
      create
    end
  end
end
于 2012-08-14T11:33:40.267 回答