TL;DR: AR::Base 保存トランザクション内に重複した結合テーブル レコードを挿入すると、(一意の制約が原因で) 保存が失敗し、ロールバックが発生します。重複した結合テーブル レコードを追加しなくても問題ありません。貯めないことは悪いことです。
私はmysqlアプリをpostgresに移行しています...私はmysql-landで次のようなパターンに従って、結合テーブルレコードをDBに追加していました:
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 のトランザクションが無効になります。これは悲しいことです。
postgres-land で使用できる、より良いパターンはありますか?
ありがとう!
編集:
このロジックをシリーズの保存トランザクション内に保持することは理にかなっていると固く信じています...パターンは次のようになります。
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.
...それは私のコントローラーを超小型にします。