3

親と子の 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_savefalse を返すと、親が保存されなくなります。コンソールと実際にデータベースを調べて確認しました。しかし、私の 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
4

1 に答える 1