Каковы поддерживаемые пути «расширения» объекта Rails?

Это разочаровывало меня в течение 1/2 дня.

Я пытаюсь расширить свою модель из файла модуля .rb, расположенного в нетипичном месте. В моей модели я пытаюсь расширить модуль на основе атрибута в модели. Модели передаются в представление, и я хочу, чтобы представление вызывало один и тот же метод модуля («контент») во всех случаях, независимо от атрибута пути модели.

 Test < ActiveRecord::Base
   ...
   after_initialization do |test|
     if !self.path.nil?
       if File.exists?('app/views/' + self.path + '/_extend.rb')
         extend 'app/views/' + self.path + '/_extend'
       end
     end
   end
   ...
 end

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

Какие-либо предложения? Спасибо.


person dubmojo    schedule 05.01.2013    source источник
comment
Это... сбивает с толку, по крайней мере, для меня. Кроме того, почему вы расширяете класс модели чем-либо из уровня представления? Вы уверены, что это подходящий способ разбить вашу функциональность?   -  person Dave Newton    schedule 06.01.2013
comment
Не обращайте внимания на путь, я не нарисовал здесь всю картину. Я только пытаюсь расширить модель с помощью модуля, который хранится в отдельном файле. Он хранится в отдельном файле, потому что позже я хотел бы создать генератор, который будет аккуратно генерировать _extend.rb и пару других файлов, специфичных для типа модели. (_config.erb и _view.erb)   -  person dubmojo    schedule 06.01.2013


Ответы (1)


метод ruby ​​extend не работает с путями. Вам необходимо предоставить модуль, который вы хотите расширить. Таким образом, вы должны хранить не path, а своего рода type, который вы сможете позже использовать для получения ссылки на модуль, который вы хотите расширить. Небольшой пример:

module GuestBehavior
  def has_access?
    false
  end
end

module AdminBehavior
  def has_access?
    true
  end
end

class User < ActiveRecord::Base
  after_initialize :extend_behavior

  def extend_behavior
    return if kind.blank?
    behavior_module = "#{kind.capitalize}Behavior".constantize
    extend behavior_module
  end
end

admin = User.new(:kind => 'admin')
guest = User.new(:kind => 'guest')

admin.has_access? # => true
guest.has_access? # => false

Это скорее эксперимент, чем код, который я на самом деле написал бы. Это должно дать вам представление о том, как достичь своей цели.

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

app/models/guest_behavior.rb
app/models/admin_behavior.rb

Вам не нужно помещать в код какие-либо операторы require. Rails автоматически загрузит файлы при доступе к GuestBehavior или AdminBehavior. (вот что делает вызов constantize)

person Yves Senn    schedule 06.01.2013
comment
Спасибо за отличный ответ. Это в основном то, что я пытаюсь сделать, но я хотел, чтобы «behaviour_module» в вашем примере исходил из отдельного файла модуля. Я хотел избежать использования «load» или «require» или написать какой-то волшебный бит, чтобы вытащить загруженные методы модуля в мою модель, чтобы я мог вызывать один и тот же метод независимо от типа. Я думаю, что я собираюсь прибегнуть к расширению моей модели из ее .rb. Это позор, потому что я хотел написать генератор для упрощения создания модели и некоторых дополнительных файлов, специфичных для типа модели. (_config.erb и _view.erb) - person dubmojo; 06.01.2013
comment
Если у вас есть предложение о том, как расширить модуль в класс из файла, я приму его. Глобальная загрузка модели была бы проблемой, потому что мне пришлось бы присваивать каждому модулю уникальное имя. (если бы они были расширены из файлов, только путь должен быть уникальным) - person dubmojo; 06.01.2013
comment
@garlicman Возможно, тогда инициализатор. Кроме того, вы добавляете любые каталоги в пути автозагрузки библиотеки. - person Dave Newton; 06.01.2013
comment
@DaveNewton Я думал об этом, но я пытался не уточнять названия модулей. Если я использую инициализатор, мне придется объявить все модули отдельно/уникально. Я надеялся оставить идентификацию модуля для расширения, посмотрев в атрибуте пути этой модели стенд с именем file.rb со стандартным именем модуля. Если у вас есть предложение о том, как сделать это в инициализаторе, я определенно прислушаюсь! - person dubmojo; 06.01.2013
comment
В конце концов я решил добавить модули расширения модели в модель .rb. Я не могу автоматически генерировать новые модули в существующий модуль, но это будет работать и будет работать. Спасибо за предложения. - person dubmojo; 06.01.2013
comment
Я обновил свой ответ, чтобы показать вам, как вы можете поместить модули в отдельные файлы. - person Yves Senn; 06.01.2013