1

以下は、親と子の間のクラス定義です:-

class System
  has_many :members, :dependent => :destroy
  accepts_nested_attributes_for :members
  attr_accessible :name, :members_attributes
  validates_presence_of :name , :members

class Member
   belongs_to :system
   attr_accessible  :name
   validates_presence_of :name
   before_create :create_physical_schema_for_user

コントローラーでは、関係全体を一度に作成します:-

@system = System.new(params[:system])
...
@system.save

子のbefore_createコールバックの1つがOCIError(ruby-oci8 gemによって発生)で失敗し、ActiveRecord ::StatementInvalidExceptionが発生するまで問題はありません。この段階では、子の関連付けの1つが保存されていなくても、親は保存されます。これがレールまたはオラクルアダプタの問題であるかどうかはわかりません。

また、参考までに、create_physical_schema_for_userメソッドは次の方法で一連のDDLを実行します:-

def self.create_physical_schema_for_user(name)
  ddl_stmt = ['...',name]
  self.connection.execute(sanitize_sql(ddl_stmt))
end

同じ問題が議論されているこれらのリンクを見つけました(コールバックが異なるだけです)

https://rails.lighthouseapp.com/projects/8994/tickets/3391-nested-attributes-vs-before_save

https://rails.lighthouseapp.com/projects/8994/tickets/3045-nested_attributes-doesnt-rollback-parent-when-before_saveafter_save-callbacks-fail

そのうちの1つは、これがRails 2でマージされたと言っていますが、Rails 3.2.5でもこの問題が発生していますが、OracleAdaptersを使用しています

1つの子の作成が失敗した場合でも、親トランザクション全体をロールバックするように、親とそのすべての関連付けを1つのトランザクションで本質的に保存するための最良の方法を知りたいです。

環境:Rails 3.2.5、Ruby 1.9.2

データベース:Oracle 11g XEからruby-oci8(2.1.2)およびactiverecord-oracle_enhanced-adapter(1.4.1)gem

4

1 に答える 1

1

開いているトランザクションを自動コミットするコールバックで DDL を使用していなければ、この問題全体は発生しませんでした。したがって、DDL の 1 つが失敗した場合でも、親は既にコミットされているため、ロールバックできません。

別のデータベース接続で DDL を実行するために次のことを行ったので、それらの失敗はモデルのトランザクションには影響せず、安全にロールバックできます。

別の接続で DDL の実行を処理するクラスを定義しました。

class SqlSystem  < ActiveRecord::Base
 establish_connection Rails.configuration.database_configuration[Rails.env]
 private
 def self.execute_ddl(stmt)
    self.connection.execute(sanitize_sql(stmt))
 end
end

メンバークラスの before_create コールバック内:-

def self.create_physical_schema_for_user(name)
  begin 
    SqlSystem.execute_ddl('...')
  rescue => error
    return false # Or Re-Raise the exception, whichever suits
  end
end

注: ActiveRecord から DDL を実行する方法が Rails ではないことはわかっていますが、DBA が本番環境を管理するためのアプリケーションを開発しています。ユーザーのプロビジョニング、権限の付与など。したがって、DDL を実行する必要があります。私はそれを行うためのより良い方法を見つけていません。

于 2012-07-21T01:07:33.997 に答える