Rails: обратные вызовы из модуля

Я пытаюсь сделать так:

приложение / модели / my_model.rb:

class MyModel <  ActiveRecord::Base
  include MyModule
  ...
end

lib / my_module.rb:

module MyModule
  before_destroy :my_func    #!

  def my_func
    ...
  end
end

но я получаю сообщение об ошибке:

undefined method `before_destroy' for MyModule:Module

Как я могу это исправить.

Также я новичок в рубине. Какой тип имеет эти «атрибуты»: before_destroy, validates, has_many? Это переменные или методы, что ли? Спасибо


person welldan97    schedule 06.03.2011    source источник


Ответы (3)


before_destroy, validates и т. Д. Не являются атрибутами или чем-то подобным. Это вызовы методов.

В ruby ​​все тело класса представляет собой исполняемый код, что означает, что каждая строка тела класса выполняется интерпретатором точно так же, как и тело метода.

before_destroy :my_func - это обычный вызов метода Ruby. Вызывается метод before_destroy, и он получает в качестве аргумента символ :my_func. Этот метод ищется в классе (или модуле), в рамках которого он вызывается.

Итак, переходя к вашему вопросу, я думаю, теперь вы должны понимать, что когда интерпретатор загружает ваш модуль

module MyModule
  before_destroy :my_func    #!

  def my_func
    ...
  end
end

он начинает выполнение своего тела и ищет метод before_destroy в этом модуле и не может его найти. Что вы хотите сделать, так это вызвать этот метод не в модуле, а в классе, в который включен модуль. Для этого у нас есть общая идиома, использующая метод Module#included:

module MyModule
  module InstanceMethods
    def my_func
      ...
    end
  end

  def self.included(base)
    base.send :include, InstanceMethods
    base.before_destroy :my_func
  end
end
person alex.zherdev    schedule 06.03.2011

В lib / my_module.rb сделайте следующее:

  class MyInheritedClass <  ActiveRecord::Base
    before_destroy :my_func
    def my_func
       ...
    end
  end

В app / models / my_model.rb сделайте следующее:

class MyModel < MyInheritedClass
  ...
end

В модуле, который вы пытаетесь создать выше, нет фильтра before_destroy. Мой код создает класс, который будет унаследован от ActiveRecord :: Base, и это будет ваш шаблонный класс, от которого могут наследовать все ваши другие классы. Класс шаблона также содержит все свойства ActiveRecord :: Base.

person RubyFanatic    schedule 06.03.2011

Вы можете исправить это, удалив before_destroy из MyModule и вместо этого поместив его в MyModel

before_destroy и другие обратные вызовы доступны только для классов, расширяющих ActiveRecord :: Base, дополнительная информация здесь

надеюсь, это поможет =)

person Staelen    schedule 06.03.2011