我正试图在控制器中调用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
生成)?
答案 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链接: