TL;DR:在 AR::Base 保存事务中插入重复的连接表记录失败(由于唯一约束)导致保存失败并回滚。不添加重复的连接表记录很好。不储蓄是不好的。
我正在将 mysql 应用程序迁移到 postgres ......我曾经在 mysql-land 中遵循类似的模式将连接表记录添加到数据库:
class EventsSeries < ActiveRecord::Base
# UNIQUE KEY `index_events_series_on_event_id_and_series_id` (`event_id`,`series_id`)
belongs_to :event
belongs_to :series
end
class Series < ActiveRecord::Base
has_many :events_series
before_validation :add_new_event
private
def add_new_event
# boils down to something like this
EventSeries.new.tap do |es|
es.event_id = 1
es.series_id = 1
begin
es.save!
rescue ActiveRecord::RecordNotUnique
# Great it exists
# this isn't really a problem
# please move on
end
end
end
end
像这样调用:
Series.first.save
# should not blow up on duplicate join record, cause i don't care
然而,postgres 对此大发雷霆。这里有一个很好的解释:
http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
...在“异常处理和回滚”部分(参见警告)
基本上#save启动一个事务,重复记录插入导致数据库异常,使#save的事务无效,这是sadface。
有没有更好的模式可以在 postgres-land 中使用?
谢谢!
编辑:
我坚信将这个逻辑保留在 Series 的保存事务中是有意义的……模式如下所示:
s = Series.new
s.new_event_id = 123 # this is just an attr_accessor
s.save # callbacks on Series know how to add the new event.
...它使我的控制器超级小。