Как добавить before_filter в gem после всех других контроллеров before_filters в приложении Rails3? - PullRequest
9 голосов
/ 16 сентября 2011

Есть драгоценный камень, который добавляет a before_filter в приложение Rails:

class Railtie < Rails::Railtie
  initializer "..." do
    ActiveSupport.on_load(:action_controller) do
      ActionController::Base.send(:include, Filter)

...

module Filter
  extend ActiveSupport::Concern

  included do
    append_before_filter :set_locale
  end

  def set_locale
     ....

И вот какой-то контроллер в приложении:

class DesktopsController < ApplicationController
  before_filter :set_language_in_session

Теперь проблема в том, что before_filter из драгоценного камня помещается в цепочку фильтров перед before_filter из DesktopsController:

DesktopsController._process_action_callbacks.select { |c| c.kind == :before }.collect { |filter| filter.filter }
=> [
    [0] :set_locale,
    [1] :set_language_in_session
]

Как я могу сделать before_filter из драгоценного камня( set_locale ) ставить после всех других фильтров?Секрет, вероятно, заключается в этой строке:

ActiveSupport.on_load(:action_controller) do

Но я пробовал разные библиотеки без какой-либо удачи ...

Кстати.Вот полный код драгоценного камня .Ruby 1.9.2, Rails 3.0.5.

Ответы [ 7 ]

3 голосов
/ 26 сентября 2011

Адаптация драгоценного камня никогда не будет работать. Драгоценный камень инициализируется как одна из первых вещей в процессе рельсов, так что еще до того, как будет запущен какой-либо реальный контроллер. Таким образом, это означает, что что бы вы ни делали, скорее всего, фильтр от драгоценного камня все равно останется первым драгоценным камнем.

Итак, единственные решения, которые я вижу:

  • с использованием prepend_before_filter в ваших собственных контроллерах для тех действий, которые должны предшествовать set_locale.
  • если вам нужен явный контроль, используйте skip_before_filter и явный before_filter.

В приложении rails 2 мы разработали хак, чтобы убедиться, что какой-то фильтр был запущен как последний фильтр, переопределив perform_action_without_filters (см. Есть ли способ заставить before_filter всегда выполняться последним? ) но мы удалили это при обновлении до рельсов 3.

2 голосов
/ 21 сентября 2011

Мой ответ основан на ответе Никгрима , который я также нашел довольно умным Блок, переданный included, получает класс, исключенный (class_eval), когда модуль включен. Вы можете сделать set_locale_filter метод класса, определив его в блоке included (среди прочего).

module Filter
  extend ActiveSupport::Concern

  included do
    append_before_filter :set_locale_filter

    def self.set_locale_filter
      append_before_filter :set_locale
    end
  end

  def set_locale
    # 
  end
end

Кто-нибудь, пожалуйста, поправьте меня, если я ошибаюсь. Здесь уже поздно:)

0 голосов
/ 24 сентября 2011

Лично я, вероятно, написал бы часть промежуточного программного обеспечения, которое выполняет вашу работу, потому что тогда вам не нужно беспокоиться о порядке фильтров.

http://guides.rubyonrails.org/rails_on_rack.html

0 голосов
/ 20 сентября 2011

Сам гем находится на Github, так что вы можете его раскошелиться и внести изменения в код, а затем получить вместо своего кода вашу версию гема.Это вариант?Если это так, вы можете просто закомментировать before_filer в драгоценном камне и назвать его самостоятельно в своем ApplicationController:

module Filter
  extend ActiveSupport::Concern

  included do
    # append_before_filter :set_locale
  end

  def set_locale
    ....

Теперь просто вызовите его сами после всех остальных фильтров:

class ApplicationController < ActionController::Base
  before_filter :do_this, :do_that, :set_locale
  ...
end

Что ты думаешь?

0 голосов
/ 20 сентября 2011

Я не пробовал, но вы могли бы проверить prepend_before_filter, который утверждает, что поставил предоставленный фильтр вверху списка (и, в конечном счете, до: set_locale).

class DesktopsController < ApplicationController
  prepend_before_filter      :set_language_in_session
end 

Документы: http://apidock.com/rails/ActionController/Filters/ClassMethods/prepend_before_filter

Еще одна вещь, которую стоит попробовать - это использовать round_filter для: set_language_in_session (даже если вы ничего не делаете после действия). Фильтры вокруг происходят до before_filters, так что это может быть хорошим способом заставить это произойти первым.

0 голосов
/ 19 сентября 2011

Не пробовал это вообще, но: вы могли бы получить у камня before_filter run append_before_filter? Что-то вроде:

module Filter
  ...

  included do
    append_before_filter :append_set_locale_filter
  end

  def append_set_locale_filter
    append_before_filter :set_locale
  end

  def set_locale
    ...
  end

  ...
end
0 голосов
/ 16 сентября 2011

Попробуйте это:

class DesktopsController < ApplicationController
  skip_before_filter :set_locale
  before_filter      :set_language_in_session
  before_filter      :set_locale
end 

Ссылка

skip_before_filter документ

...