Как я могу переопределить метод модуля Ruby on Rails через метапрограммирование? - PullRequest
2 голосов
/ 12 февраля 2010

Как бы мне ни хотелось, я до сих пор не знаю, как реализовать метапрограммирование.

Для представлений, отображаемых с моего контроллера Admin :: Base, я бы хотел переопределить Rails compute_public_path, расположенный в ActionView :: Helpers :: AssetTagHelper, чтобы все файлы макетов моего администратора были в public / admin.

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

Я положил это в Admin :: Базовый контроллер:

module ActionView::Helpers::AssetTagHelper
  def compute_public_path(source, dir, ext = nil, include_host = true)
    super(source, "admin/#{dir}", ext = nil, include_host = true)
  end
end

но это дает мне:

super: no superclass method `compute_public_path' for #<ActionView::Base:0x1032240a8>

Что меня не удивляет.


Если я попробую это в моем помощнике администратора:

def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
  compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
end

alias_method_chain :compute_public_path, :admin

Я получаю "неопределенный метод 'compute_public_path' для модуля 'AdminHelper'", что, как я предполагаю, происходит потому, что compute_public_path - это закрытый метод.

Я нашел это работает:

ActionView::Helpers::AssetTagHelper.class_eval do
  def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
    compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
  end

  alias_method_chain :compute_public_path, :admin
end

, пока я устанавливаю config.cache_classes в false, в противном случае я получаю слишком большую ошибку на уровне стека.

Спасибо Squeegy за указание в правильном направлении.

Как я могу заставить эту работу отключить кэширование классов?

Ответы [ 2 ]

1 голос
/ 12 февраля 2010
def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
  compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
end

alias_method_chain :compute_public_path, :admin

compute_public_path теперь будет вызывать вашу реализацию, которая затем вызывает исходную реализацию.

См .: Является ли alias_method_chain синонимом alias_method?

0 голосов
/ 21 октября 2014

Пожалуйста, не делайте этого.

Принятый ответ получит то, что вы хотели, но то, что вы хотите, может иметь опасные последствия для безопасности.

Почему вы хотите, чтобы макеты вашего администратора были под public? Есть причина, по которой Rails по умолчанию ставит их под app/views/layouts: никто не сможет прочитать их источник там.

Если вы введете их в public, они в основном читабельны для любого посетителя.

Если вы разместите их там, где они должны быть, вы не будете раскрывать свой код макета. И, вдобавок ко всему, вы можете структурировать app/views/layouts любым удобным для вас способом без какого-либо метапрограммирования , то есть без необходимости взламывать внутренние компоненты фреймворка.

...