Включить модуль в класс ruby в инициализаторе Rails

#ruby-on-rails #ruby #module #include #actiondispatch

#ruby-on-rails #ruby #модуль #включить #actiondispatch

Вопрос:

Внутри инициализатора в Rails я пытаюсь включить модуль в модель rails

 User.send :include, Something
  

Это работает для первого запроса, но не для второго / третьего / и т.д. Из-за перезагрузки модели rails. Я пытался использовать ActionDispatch::Callbacks.to_prepare (ActionDispatch::Callbacks.to_prepare, я использую Rails 3.0.9)

 ActionDispatch::Callbacks.to_prepare do
  User.send :include, Something
end
  

но я продолжаю получать ошибку NoMethod от экземпляра пользователя, когда я пытаюсь вызвать метод, определенный в моем модуле module, по второму / третьему / etc. запросу.

Мой вопрос заключается в следующем: есть ли способ надежно включить модуль в модель Rails в инициализаторе без каких-либо странностей в разработке?

Обновление: невозможно

По-видимому, это невозможно сделать без промежуточного программного обеспечения. Если вы не согласны, добавьте ответ ниже. Это не было приемлемым решением для моего варианта использования, поэтому я на самом деле даже не пробовал. Удачи.

Редактировать: обновлена информация об отладке

Я еще немного поиграл с ActionDispatch::Callbacks.to_prepare и заметил что-то странное, когда вставил это в свой инициализатор:

 ActionDispatch::Callbacks.to_prepare do
  puts "to_prepare ==:#{User.object_id}"
end
  

и это в моем контроллере

 puts "controller ==:#{User.object_id}"
  

по первому запросу я получаю это:

 to_prepare ==: 2297196200
controller ==: 2297196200
to_prepare ==: 2297196200
to_prepare ==: 2324202920
to_prepare ==: 2318560780
  

по второму запросу я получаю это:

 to_prepare ==: 2326823900
controller ==: 2326823900
to_prepare ==: 2317901920
to_prepare ==: 2326746040
to_prepare ==: 2314369160
  

Первое, что я заметил, было несколько вызовов to_prepare, что странно. Вторая вещь, которую я заметил, была в первом запросе (который работает), object_id непосредственно перед и после вызова контроллера одинаковы, и они не присутствуют ни в каких последующих вызовах. Если бы кто-нибудь мог пролить некоторый свет на то, почему это происходит и как это обойти, это было бы очень ценно.

Комментарии:

1. Есть ли причина, по которой это должно быть сделано в инициализаторе? включить что-либо в пользовательскую модель будет работать в любой среде.

2. @bandito, это упрощенная версия моей проблемы. Есть причина, по которой это необходимо сделать в инициализаторе… слишком долго, чтобы вдаваться в подробности. Короче говоря, я превращаю это в драгоценный камень, и одному классу необходимо знать другие классы, которые реализуют интерфейс. Это не первый раз, когда я хотел сделать что-то подобное, и мне помешала перезагрузка модели разработки Rails.

3. Rails перезагружает ваши контроллеры и модели (и другие вещи) между запросами в процессе разработки. Первый запрос вряд ли будет таким же, как все последующие запросы. Я не знаю, что это за внутренние компоненты (вам нужно будет прочитать исходный код на github), но именно поэтому вы видите, что object_id изменяется таким образом. Именно поэтому я думаю, что об инициализаторе не может быть и речи, поскольку он не выполняется для каждого запроса.

4. Если вы пишете gem, вы, вероятно, могли бы использовать raildies для внедрения промежуточного программного обеспечения, не затрагивая этим пользователя.

Ответ №1:

Помогает ли использование config.after_initialize крючка? Это проблема, зависящая от среды разработки, из-за перезагрузки класса.

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

 class AddYourModuleMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    User.send(:include, YourModule) unless User < YourModule
    @app.call(env)
  end
end
  

Добавьте его в цепочку промежуточного программного обеспечения с помощью config.middleware.use AddYourModuleMiddleware или, альтернативно, разместив use AddYourMiddleware в начале ApplicationController .

Комментарии:

1. Вы пробовали это? User.object_id Отличается ли контроллер от промежуточного программного обеспечения? Хотя это интересное предложение, должен быть способ сделать это, не требуя, чтобы я помещал промежуточное программное обеспечение в свой gem.

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