2012-03-14 2 views
2

модель "One"Как избежать двойного сохранения модели ActiveRecord?

class One < ActiveRecord::Base 
    before_save :do_stuff 

    private 
    def do_stuff 
     two = Two.find(8) 
     two.field2 = 'Value' 
     two.save! 
    end 
end 

Модель "Два"

class Two < ActiveRecord::Base 
    before_save :do_stuff 

    private 
    def do_stuff 
     one = One.find(7) 
     one.field2 = 'SomeValue' 
     one.save! 
    end 
end 

Выполнение:

two = Two.find(1) 
two.somefield = 'NewVal' 
two.save! 

Бесконечный цикл начнется. Что будет с Ruby-on-rails для реализации двух моделей, которые должны изменить друг друга на обратном вызове before_save?

+0

Что именно вы пытаетесь достичь здесь? –

+2

Несомненно, у вас возникли проблемы с дизайном, даже если вы решите текущий вопрос, это приведет вас к следующей проблеме: – megas

+0

+1, даже если это выглядит как недостаток в дизайне, я нашел себя более одного раза в этом _cycle ссылка обратного вызова hell_. Может быть полезно иметь возможность [Избегать обратных вызовов adhoc] (http://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks) – fguillen

ответ

2

Надеемся, что вам нужно будет отключить ваш фильтр before_save с помощью attr_accessor или переместить его в блок after_save, чтобы избежать цикла.

Например:

class One < ActiveRecord::Base 
    attr_accessor :not_doing_stuff 
    before_save :do_stuff, 
    :unless => :not_doing_stuff 

private 
    def do_stuff 
    two = Two.find(8) 
    two.field2 = 'Value' 
    two.save! 
    end 
end 

Вы бы отключить триггер, по меньшей мере, один из них:

class Two < ActiveRecord::Base 
    before_save :do_stuff 

private 
    def do_stuff 
    one = One.find(7) 
    one.not_doing_stuff = true 
    one.field2 = 'SomeValue' 
    one.save! 
    end 
end 

вещи, как это всегда очень некрасиво, поэтому постарайтесь не избежать его, если вы можете не думайте иначе. Если вам это нужно, убедитесь, что вы написали достаточно модульных тестов, чтобы убедиться, что они не будут блокироваться в бесконечном цикле в некоторых случаях.

+0

очень умный .. нравится! :) – fguillen

1

Не вызывайте save в before_save: он вызовет бесконечный цикл. Вернуть true или false вместо этого - true, если все, что вы положили в before_save, было выполнено, false, если оно не выполнено. Возврат false отменяет сохранение и все другие обратные вызовы.

Смежные вопросы