From: Josh Cheek Date: 2013-02-20T12:47:10+09:00 Subject: Re: ActiveRecord callback chain exception? --bcaec554d5dee20c9804d61fcf1e Content-Type: text/plain; charset=ISO-8859-1 On Tue, Feb 19, 2013 at 7:21 PM, Craayzie As a fox wrote: > I'm creating an ActiveRecord object A and want to update object B during > the process even if the creation of object A is rolled back due to a > before_create callback returning false. > > Is there a way for me to do this? > > It seems that once you're in the ActiveRecord callback chain your DB > updates will be rolled back unless the entire callback chain returns > true. > > Another way to look at this: I need to track all ActiveRecord "create" > attempts but it seems that I'm unable to use callbacks or observers to > do this since both are referenced within the ActiveRecord callback > chain. > > How would you go about doing this? > > Thanks for the help! > > -- > Posted via http://www.ruby-forum.com/. > > You could use a database level trigger, e.g. http://www.postgresql.org/docs/9.1/static/sql-createtrigger.html I don't know your needs, but I generally try to avoid things like this, because it means you can't create the A without the B being created. It is better to have this available, but not mandatory (don't couple your future use to your current use). So I'd maybe make some method whose job is to create the record and record the attempt whether it passes or fails (IOW, do not use the callback). Something like this: require 'active_record' ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:' ActiveRecord::Schema.define do self.verbose = false create_table(:as) { |t| t.string :s } create_table :bs do |t| t.string :initialization_attributes t.boolean :success end end class A < ActiveRecord::Base validates :s, format: { with: /x/ } end class B < ActiveRecord::Base def self.record(attributes) A.new attributes do |obj| create! initialization_attributes: attributes, success: obj.save end end serialize :initialization_attributes end B.record(s: 'x').persisted? # => true B.record(s: 'y').persisted? # => false A.count # => 1 B.count # => 2 x, y = B.all x # => #"x"}, success: true> y # => #"y"}, success: false> The downside is you lose the ability to do things like c.as.build(attributes) -Josh --bcaec554d5dee20c9804d61fcf1e Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Tue, Feb 19, 2013 at 7:21 PM, Craayzie As a fox <lists@ruby-forum.co= m> wrote:
I'm creating an ActiveRecord object A and want to update object B durin= g
the process even if the creation of object A is rolled back due to a
before_create callback returning false.

Is there a way for me to do this?

It seems that once you're in the ActiveRecord callback chain your DB updates will be rolled back unless the entire callback chain returns
true.

Another way to look at this: I need to track all ActiveRecord "create&= quot;
attempts but it seems that I'm unable to use callbacks or observers to<= br> do this since both are referenced within the ActiveRecord callback
chain.

How would you go about doing this?

Thanks for the help!

--
Posted via http://= www.ruby-forum.com/.


You could use a database le= vel trigger, e.g.=A0http://www.postgresql.org/docs/9.1/static/sql-createt= rigger.html

I don't know your needs, but I generally try to avoid th= ings like this, because it means you can't create the A without the B b= eing created. It is better to have this available, but not mandatory (don&#= 39;t couple your future use to your current use).

So I'd maybe make some method whose job is to create the = record and record the attempt whether it passes or fails (IOW, do not use t= he callback).

Something like this:


require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', = database: ':memory:'
ActiveRecord::Schema.define do
=A0 self.verbose =3D false
=A0 create_table(:as) { |t| t.str= ing :s } =A0
=A0 create_table :bs do |t|
=A0 =A0 t.stri= ng =A0:initialization_attributes
=A0 =A0 t.boolean :success
=
=A0 end
end

class A < ActiveRecord::Base
=A0 validates :s, format: { with: /x/ }
end

=
class B < ActiveRecord::Base
=A0 def self.record(attribut= es)
=A0 =A0 A.new attributes do |obj|
=A0 =A0 =A0 create! initia= lization_attributes: attributes, success: obj.save
=A0 =A0 end
=A0 end
=A0=A0
=A0 serialize :initialization_at= tributes
end

B.record(s: 'x').persisted? # =3D> = true
B.record(s: 'y').persisted? # =3D> false

A.count # =3D> 1
B.count # =3D> 2

x, y =3D B.all
x # =3D> #<B id: 1, initializatio= n_attributes: {:s=3D>"x"}, success: true>
y # =3D= > #<B id: 2, initialization_attributes: {:s=3D>"y"}, suc= cess: false>


The downside is you lose the abili= ty to do things like c.as.build(attributes)

-Josh<= /div> --bcaec554d5dee20c9804d61fcf1e--