Rails 5:具有唯一约束的update_attributes

时间:2017-01-18 18:32:44

标签: ruby-on-rails ruby ruby-on-rails-5

我正试图在控制器中调用find_or_initialize_by,如下所示:

@lead = Lead.find_or_initialize_by(external_id: lead['external_id'])
@lead.update_attributes(lead)

这一切都很好,但我的问题是lead可以而且应该有一些信息对我的模型有独特的限制:

validates :address, uniqueness: { scope: [:address, :city, :state, :zip] }
validates :voter_id, uniqueness: true
validates :external_id, uniqueness: true
validates :email, uniqueness: true, allow_blank: true, allow_nil: true
validates_presence_of :first_name, :last_name, :address, :city, :state, :zip, :source, :status

因此,当数据库中已经存在一个线索时,update_attributes会失败,因为哈希包含记录已经执行的相同信息(加上非唯一的区别):

ActiveRecord::RecordInvalid (Validation failed: Address has already been taken, Voter has already been taken, External has already been taken):

如何在保持所有验证的同时传递此哈希并让Rails保存它,无论它是新的(由initialize_by生成)还是现有的(由find生成)?

3 个答案:

答案 0 :(得分:1)

在内部,update_attributes调用assign_attributes,它分配给定的属性并覆盖现有值(如果它们不同)。但是,如果之前已分配了相同的值,则此属性不会被视为已更改,因此不会包含在更新的查询中。

如果一切都是应有的,那么您的唯一性验证应该不会失败 - 无论是新记录还是现有记录。我认为,还有一些其他的怪癖(在提供的有关您的上下文的信息中不可见)导致这些错误,并建议不要简单地禁用验证。

答案 1 :(得分:0)

对于Rails 5,请使用update_attribute代替update_attributes

更新单个属性并保存记录,而无需通过正常的验证程序。

注意:' update_attribute'从我们认为的代码中一次只更新一个属性,我认为它对您有用。

如果此方法不适合您,您也可以使用.update_columns found here

答案 2 :(得分:0)

@lead = Lead.find_or_initialize_by(external_id: lead['external_id'])
@lead.attributes = lead
@lead.save(validate: false)

这应该可以解决问题 不知道为什么你会绕过你的验证,这会在以后咬你。

Api链接: