#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%, что это сработает, поскольку мы используем промежуточное программное обеспечение для других вещей, которые нам нужно сделать для подготовки запроса.