How to prevent database changes inside Rails ActiveRecord before the before_create filter when rolling back when it returns false?

I added a before_create filter to one of my Rails ActiveRecord models, and inside this filter I am doing some database updates.

Sometimes I return false from the filter to prevent the creation of the target model, but this causes all other database changes that I made (while inside the filter) to go back.

How can I prevent this?

Update # 1 . Here is some kind of pseudo code explaining my problem:

class Widget < ActiveRecord::Base
  before_create :update_instead

  def update_instead
    if some_condition?
      update_some_record_in_same_model # this is getting rolled back
      return false # don't create a new record
    else
      return true # let it continue
    end
  end
end

Update # 2 . A few good answers below, but each has its own flaws. I ended up redefining the creation method like this:

def create
  super unless update_instead? # yes I reversed the return values from above
end
+3
5

. AR. . , , .

. , , .

class Foo < ActiveRecord::Base
  before_create :update_instead

  def update_instead
    dbconn = self.class.connection_pool.checkout
    dbconn.transaction do
      dbconn.execute("update foos set name = 'updated'")
    end
    self.class.connection_pool.checkin(dbconn)
    false
  end
end


>> Foo.create(:name => 'sam')
=> #<Foo id: nil, name: "sam", created_at: nil, updated_at: nil>
>> Foo.all
=> [#<Foo id: 2, name: "updated", created_at: "2009-10-21 15:12:55", updated_at: "2009-10-21 15:12:55">]
+2

.

+2

create/save ? ActiveRecord:: Base.create, ActiveRecord:: Base.save , , . , , , . , , .

:

before_create :before_create_actions_that_can_be_rolled_back

def create
  if valid? && before_create_actions_that_wont_be_rolled_back
    super
  end
end

def before_create_actions_that_wont_be_rolled_back
 # exactly what it sounds like
end

def before_create_actions_that_can_be_rolled_back
 # exactly what it sounds like
end

: :

  1. (on_create)
  2. Validate
  3. (on_create)
  4. before_create_actions_that_wont_be_rolled_back
  5. (on_create)
  6. Validate
  7. (on_create)

- - false 5-12, , 5.

? fail, before_create_actions_that_wont_be_rolled_back , .

+1

after_create ?

0

, Rich Cavanaugh. , , . + / . : , 2 , , . , 5.

class Gadget < ActiveRecord::Base
  has_many :widgets
end

class Widget < ActiveRecord::Base
  belongs_to :gadget
  before_create :update_instead

  def update_some_record_in_same_model
    # the thread forces a new connection to be checked out
    Thread.new do
      ActiveRecord::Base.connection_pool.with_connection do |conn|
        # try this part without the 2 surrounding blocks and it will be rolled back
        gadget.touch_count += 1
        gadget.save!
      end
    end.join
  end
  def some_condition?
    true
  end

  def update_instead
    if some_condition?
      update_some_record_in_same_model # this is getting rolled back
      p [:touch_count_in_filter, gadget.reload.touch_count]
      return false # don't create a new record
    else
      return true # let it continue
    end
  end
end

:

  g = Gadget.create(:name => 'g1')
  puts "before:"
  p [:touch_count, g.reload.touch_count]
  p [:widget_count, Widget.count]

  g.widgets.create(:name => 'w1')
  puts "after:"
  # Success means the count stays incremented
  p [:touch_count, g.reload.touch_count]
  p [:widget_count, Widget.count]

: http://bibwild.wordpress.com/2011/11/14/multi-threading-in-rails-activerecord-3-0-3-1/

0

Source: https://habr.com/ru/post/1720616/


All Articles