Можно ли добавить обратный вызов сохранения к одному экземпляру ActiveRecord? - PullRequest
5 голосов
/ 22 марта 2010

Можно ли добавить обратный вызов к одному экземпляру ActiveRecord? Еще одним ограничением является использование библиотеки, чтобы у меня не было контроля над классом (за исключением того, что я его исправил).

Это более или менее то, что я хочу сделать:

def do_something_creazy
  message = Message.new
  message.on_save_call :do_even_more_crazy_stuff
end

def do_even_more_crazy_stuff(message)
  puts "Message #{message} has been saved! Hallelujah!"
end

Ответы [ 5 ]

5 голосов
/ 22 марта 2010

Вы можете сделать что-то подобное, добавив обратный вызов к объекту сразу после его создания и, как вы сказали, применив обезьяны-исправления по умолчанию, метод AR before_save:

def do_something_ballsy
    msg = Message.new
    def msg.before_save(msg)
        puts "Message #{msg} is saved."
        # Calls before_save defined in the model
        super
    end
end
3 голосов
/ 22 марта 2010

Для чего-то подобного вы всегда можете определить свои собственные сумасшедшие обработчики:

class Something < ActiveRecord::Base
  before_save :run_before_save_callbacks

  def before_save(&block)
    @before_save_callbacks ||= [ ]
    @before_save_callbacks << block
  end

protected
  def run_before_save_callbacks
    return unless @before_save_callbacks

    @before_save_callbacks.each do |callback|
      callback.call
    end
  end
end

Это можно сделать более общим или расширением ActiveRecord :: Base, в зависимости от области вашей проблемы. Использовать его должно быть легко:

something = Something.new

something.before_save do
  Rails.logger.warn("I'm saving!")
end
1 голос
/ 09 июля 2015

Следующее позволит вам использовать обычную конструкцию before_save, то есть вызывать ее в классе, только в этом случае вы вызываете ее в метаклассе экземпляра, чтобы другие экземпляры Message не затрагивались. (Протестировано в Ruby 1.9, Rails 3.13)

msg = Message.new
class << msg
  before_save -> { puts "Message #{self} is saved" } # Here, `self` is the msg instance
end
Message.before_save # Calling this with no args will ensure that it gets added to the callbacks chain (but only for your instance)

Проверьте это так:

msg.save         # will run the before_save callback above
Message.new.save # will NOT run the before_save callback above
1 голос
/ 24 марта 2014

Чтобы добавить к ответу bobthabuilda - вместо определения метода в метаклассе объектов расширьте объект модулем:

def do_something_ballsy
  callback = Module.new do   
    def before_save(msg)
      puts "Message #{msg} is saved."
      # Calls before_save defined in the model
      super
    end
  end
  msg = Message.new
  msg.extend(callback)
end

Таким образом, вы можете определить несколько обратных вызовов, и они будут выполнятьсяв обратном порядке вы их добавили.

1 голос
/ 18 декабря 2013

Я хотел использовать этот подход в своем собственном проекте, чтобы иметь возможность вводить дополнительные действия в действие «сохранить» модели из уровня моего контроллера. Я взял ответ Тадмана на шаг вперед и создал модуль, который можно внедрить в классы активной модели:

module InstanceCallbacks 
  extend ActiveSupport::Concern

  CALLBACKS = [:before_validation, :after_validation, :before_save, :before_create, :after_create, :after_save, :after_commit]

  included do
    CALLBACKS.each do |callback|
      class_eval <<-RUBY, __FILE__, __LINE__
        #{callback} :run_#{callback}_instance_callbacks

        def run_#{callback}_instance_callbacks
          return unless @instance_#{callback}_callbacks
          @instance_#{callback}_callbacks.each do |callback|
            callback.call
          end
        end

        def #{callback}(&callback)
          @instance_#{callback}_callbacks ||= []
          @instance_#{callback}_callbacks << callback
        end
      RUBY
    end
  end
end

Это позволяет вам внедрить полный набор обратных вызовов экземпляра в любую модель, просто включив модуль. В этом случае:

class Message
  include InstanceCallbacks
end

И тогда вы можете делать такие вещи, как:

m = Message.new
m.after_save do
  puts "In after_save callback"
end
m.save!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...