我有创造新记录潜在具有相同(也新建)儿童问题的对象。为了方便起见,我们假设我有一个名为rules
的表(如防火墙的访问控制列表中的规则)和名为ips
的表包含名为ip_str
的单个UNIQUE INDEX
ed属性。合并Rails的平等属性
要创建Rule
,需要源Ip
和目标Ip
。
class Rule < ActiveRecord::Base
belongs_to :src_ip, class_name: Ip.name
belongs_to :dest_ip, class_name: Ip.name
end
的情况并不少见使用Rule
像deny ip any any
,这对我们来说就相当于
src = Ip.where(ip_str: "any").first_or_initialize()
dest = Ip.where(ip_str: "any").first_or_initialize()
rule = Rule.new(src_ip: src, dest_ip: dest)
rule.save()
#=> throws error: duplicate entry
明显的问题在这里,当我尝试保存Rule
和有在数据库中没有Ip
与ip_str = "any"
,Rails的在内存中保持两个独立Ip
-objects并尝试一个接一个将其保存。因此,保存第一个Ip
成功,然后它试图保存第二个Ip
,它认为它还不存在,并且由于UNIQUE INDEX
而导致错误结束。有没有办法告诉Rails在尝试保存之前合并内存中的“重复”对象?
上面给出的例子中的一个明显的解决办法是以下
src = Ip.where(ip_str: "any").first_or_initialize()
dest = Ip.where(ip_str: "any").first_or_initialize()
dest = src if (src.ip_str == dest.ip_str)
rule = Rule.new(src_ip: src, dest_ip: dest)
rule.save()
#=> always succeeds
可悲的是真实的世界是复杂得多,我可能在differenct孩子的同时节省了大量的记录楷模。是的,UNIQUE INDEX
是至关重要的。
也许这是可以接受的,你使用'first_or_create'取代'first_or_initialize'?随着您保存第一个'Ip',下次你再节省一个(具有相等的attrs),你只得到以前保存的第一个。两个变量 - 一个对象。 – VAD
谢谢,你是对的,瞬间就被初始化将解决保存模型对象。在这种情况下,我必须包装整个代码块,它负责在一个'transaction'中创建一个对象及其子元素,因此可以顺利地'回滚';但不知道这样做是否也能平稳地生成所有activerecord错误,因为只要发生第一个错误就会中止事务。 – Brauser
很高兴这个解决方案在你的用例中很有用。添加它作为答案 – VAD