Переопределение помощников пути в Rails с использованием define_method - PullRequest
0 голосов
/ 23 мая 2018

Мне нужно переопределить несколько вспомогательных методов пути в Ruby on Rails и вызывать super из них.Мой стандартный подход:
path_helper.rb

def business_path(business)
  if params[:city_id] == 2
    moscow_business_path(business)
  else
    super
  end
end

Но у меня есть много этих методов, поэтому я хочу определить их динамически следующим образом:

  %i[root businesses business ...].each do |path_method|
    method_name = "#{path_method}_path"
    old_method = method(method_name)
    define_method(method_name) do |*args|
      if params[:city_id] == 2
        public_send("moscow_#{method_name}")
      else
        old_method.call(*args)
      end
    end
  end

Но я получаю эту ошибку:

 /home/leemour/Ruby/burobiz/app/helpers/path_helper.rb:31:in `method': undefined method `root_path' for class `Module' (NameError) 
 from /home/leemour/Ruby/burobiz/app/helpers/path_helper.rb:31:in `block in <module:PathHelper>'
 from /home/leemour/Ruby/burobiz/app/helpers/path_helper.rb:29:in `each' 
 from /home/leemour/Ruby/burobiz/app/helpers/path_helper.rb:29:in `<module:PathHelper>' 
 from /home/leemour/Ruby/burobiz/app/helpers/path_helper.rb:1:in `<top (required)>' 
 from /home/leemour/.rbenv/versions/2.3.3/lib/ruby/gems/2.3.0/gems/activesupport-5.1.3/lib/active_support/dependencies.rb:476:in `load'

Я полагаю, что вспомогательные модули еще не были включены, поэтому нет никакого исходного вспомогательного метода пути для захвата с помощью method(method_name).Тогда я думаю, что мне придется использовать self.included крючок, но я не мог понять это.Как я могу настроить этот код, чтобы он работал?(Я не хочу использовать eval).

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вы можете просто обернуть все свои вызовы

def path_name_for(path_name,*args) 
  path = "#{path_name}_path"
  path.prepend("moscow_") if params[:city] == 2
  public_send(path,*args)
end 

Тогда в ваших представлениях просто позвоните

<%= link_to 'Business Path', path_name_for(:business, @business) %>

Это делает маршрутизацию немного более понятной для меня, так как делает ее немногоболее очевидно, что существует пользовательская реализация, а не переопределяющая известную реализацию.

Также это тоже может быть возможностью (хотя и не проверено, это должно работать как ваш существующий код в "path_helper.rb")

module PathHelper
  module MoscowRedirect
    def self.prepended(base) 
      %i[...].each do |path_name|
        define_method("#{path_name}_path") do |*args|
          params[:city] == 2 ? public_send("moscow_#{__method__}",*args) : super(*args)
        end
      end
    end
  end
  self.prepend(MoscowRedirect)
end 
0 голосов
/ 23 мая 2018

Вместо того, чтобы пытаться использовать Kernel.method, вы пытались использовать метод Rails.application.routes.url_helpers?

%i[...].each do |path_method|
  define_method("#{path_method}_path") do |*args|
    if params[:city_id] == 2
      public_send("moscow_#{path_method}_path", *args)
    else
      Rails.application.routes.url_helpers.public_send("#{path_method}_path", *arsg)
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...