親と子の 2 つのモデルがあります (以下で説明します)。子モデルには、before_save
いくつかの外部ロジックを処理するためのコールバックがあり、エラーが発生した場合、コールバックは保存されているモデルを無効にします。
class Parent < ActiveRecord::Base
has_one :child
accepts_nested_attributes_for :child
validates :child, :presence => true
validates_associated :child
end
class Child < ActiveRecord::Base
belongs_to :parent
before_save :external_logic
validates :parent, :presence => true
def external_logic
begin
# Some logic
rescue
#Invalidate child model
errors.add(:base, "external logic failed")
return false
end
end
end
私が直面している問題は、親モデルのネストされた属性を介して子モデル インスタンスが作成されることです。外部ロジックが失敗した場合、子モデルと親モデルを保存せずに、親モデルを単独で保存したい。どうすればこれを達成できますか?
私は検証コールバックを認識していますが、この場合には適していません。子モデルのコールバックは before_save でなければなりません。
編集#1
私はすでにトランザクションについて知っていますが、誰かが私に「ねえ、外部でトランザクションをラップしてください」と言ったのは有効な応答であるとは考えていません。この質問は、before_save 呼び出しを使用してこの問題を解決する方法について明示的に示しています。
作成時に検証を使用できない理由 - コメントで述べたように、外部のロジックは、データベースを保存する前にのみ実行されることを保証する必要があります。検証呼び出しは、データベース レコードの変更の有無にかかわらず複数回発生する可能性があるため、このロジックを配置する場所は不適切です。
編集#2
どうやらbefore_save
false を返すと、親が保存されなくなります。コンソールと実際にデータベースを調べて確認しました。しかし、私の rspec テストはそうではないことを教えてくれます。これは奇妙なことです。特に、これは失敗しています:
describe "parent attributes hash" do
it "creates new record" do
parent = Parent.create(:name => "name", :child_attributes => {:name => "childname"})
customer.persisted?.should be_false
end
end
それはちょっとした rspec/factory_girl の奇妙さでしょうか?
編集#3
テスト エラーは、Rspec でトランザクション フィクスチャを使用しているためです。そのため、オブジェクトが実際にはデータベースに永続化されていないのに、オブジェクトがデータベースに永続化されていると誤って通知するテストが発生していました。
config.use_transactional_fixtures = true