Rails3: HOWTO Переопределение / повторное открытие класса в Gem и процессе инициализации Rails - PullRequest
2 голосов
/ 05 ноября 2010

Мой вопрос очень похож на этот: Как добавить метод в рубиновый драгоценный камень без редактирования источника драгоценного камня? .Однако этому вопросу уже почти год, и решение, которое было выбрано, не самое чистое, по крайней мере мне.

Человек, предоставивший ответ, предложил 3 предложения.Первое предложение было выбрано в качестве ответа, но мне бы очень хотелось выяснить, как это сделать вторым способом.

Мне нужно переопределить метод экземпляра класса, который определяется Gem.Более конкретно, это класс SessionSerializer в 1.1.2 Devise .Проблема в том, что Devise не уважает нестандартные имена первичных ключей.Он всегда использует id.Вы можете видеть, что в warden_compat.rb в строке 30 используется следующее для поиска модели по ее идентификатору:

klass.constantize.find(:first, :conditions => { :id => id })

В моем случае имя моего idстолбец application_user_id, поэтому очевидно, что это не сработает.Devise исправил эту проблему в 1.1.3, однако я не могу использовать 1.1.3, потому что подключаемый модуль Devise LDAP Authenticatable не поддерживает 1.1.3.

Итак, вот что я сделал вместо этого.Прежде всего, я должен упомянуть, что я протестировал это исправление путем непосредственного редактирования исходного кода Gem, поэтому теперь я просто хочу переместить его в свой проект.

  1. Создан файл session_serializer.rb в lib/warden/ (т.е.lib/warden/session_serializer.rb), вновь открыл класс Warden::SessionSerializer и переопределил метод deserialize.
  2. Изменено application.rb, чтобы включить lib/ в config.autoload_paths

    config.autoload_paths += ["#{config.root}/lib"]
    

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

Вопросы

  1. Что я здесь не так делаю?
  2. Загружает ли Rails файлы определенных путейв config.autoload_paths до Gems или наоборот?

Заранее спасибо за помощь!

lib / warden / session_serializer.rb

module Warden

  class SessionSerializer
    def deserialize(keys)
      klass, id = keys

      if klass.is_a?(Class)
        raise "Devise changed how it stores objects in session. If you are seeing this message, " <<
          "you can fix it by changing one character in your cookie secret, forcing all previous " <<
          "cookies to expire, or cleaning up your database sessions if you are using a db store."
      end
      # NOTE: Original line code. Notice that it uses an :id symbol. It doesn't respect the primary key that explicity defined in the model
      # klass.constantize.find(:first, :conditions => { :id => id })
      # NOTE: THIS IS THE FIX
      klass.constantize.find(:first, :conditions => { :application_user_id => id })
    rescue NameError => e
      if e.message =~ /uninitialized constant/
        Rails.logger.debug "Trying to deserialize invalid class #{klass}"
        nil
      else
        raise
      end
    end
  end

end

Ответы [ 2 ]

3 голосов
/ 05 ноября 2010

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

Чтобы поместить патч в каталог lib, выполните следующие действия:

config.autoload_paths += ["#{config.root}/lib/warden"]

PS: Я знаю, что вы пробовали это, но, похоже, ваш путь неверен.

PPS Чтобы понять последовательность загрузки Rails 2.3, обратитесь к этому коду .

0 голосов
/ 05 ноября 2010
...