Как я могу глобально переопределить помощник URL рельсов?

Мне нужно было добавить простое изменение в foo_path, поэтому я сделал это:

module ApplicationHelper
  # [...]

  def foo_path(foo, options = {})
    options.merge!(bar: foo.some_attribute)
    super
  end

  # [...]
end

Теперь это работает при вызове из представления, но при вызове из контроллера используется оригинальный вариант без моих дополнений.

Как я могу переопределить соответствующие приложения помощников (_path/_url) в целом?

4 ответа

Я думаю, что самый чистый способ добиться этого - это настроить routes.rb файл (по крайней мере для статических параметров по умолчанию). Документы: http://guides.rubyonrails.org/routing.html

Пример параметра по умолчанию:

get "/foo(/:bar)" => "my_controller#index", defaults: { bar: "my_default" }

Пример значения параметра по умолчанию + область действия:

scope '/(:rec_type)', defaults: { rec_type: 'mammo' }, rec_type: /mammo|face/ do
  resources :patients
end

Другие варианты (для динамических ограничений):

Расширенные ограничения маршрутизации:

Если вам нужны более продвинутые / динамические ограничения, ознакомьтесь с этим руководством: http://guides.rubyonrails.org/routing.html.

Переопределить default_url_options:

Также вы можете переопределить default_url_options Метод автоматического добавления некоторых атрибутов (параметров) с помощью помощников маршрутов: http://guides.rubyonrails.org/action_controller_overview.html.

Вы можете установить глобальные параметры по умолчанию для генерации URL, определив метод default_url_options в вашем контроллере. Такой метод должен возвращать хеш с желаемыми значениями по умолчанию, ключи которого должны быть символами:

class ApplicationController < ActionController::Base
  def default_url_options(options = {})
    if action_name == 'foo' # or other conditions
      options[:bar] = 'your_defaults' # add here your default attributes
    end

    options
  end
end

Переопределить to_param:

Системные вызовы маршрутизации Rails to_param на моделях, чтобы получить значение для :id заполнитель. ActiveRecord::Base#to_param возвращает идентификатор модели, но вы можете переопределить этот метод в ваших моделях. Например, учитывая:

class Product < ActiveRecord::Base
  def to_param
    "#{id}-#{title}"
  end
end

Это будет генерировать: /products/254-Foo

В Rails 3 и 4 все помощники маршрутизации находятся в этом модуле. Rails.application.routes.url_helpers, Таким образом, мы можем включить модуль для переопределения методов внутри него.

module FooUrlHelper
  def foo_path(foo, options = {})
    options.merge!(bar: foo.some_attribute)
    super
  end
end

# Works at Rails 4.2.1
Rails.application.routes.url_helpers.send(:include, FooUrlHelper)

# For Rails 4.2.6, I thought the following worked, but there seems to be issues, don't have time to figure out a solution yet
Rails.application.routes.named_routes.url_helpers_module.send(:include, FooUrlHelper)

Вы можете просто поместить это в инициализаторы

Я попробовал это в консоли и контроллере, и, кажется, работает нормально.

Похоже, вы столкнулись с неправильным путем. Вам лучше добавить:bar param в ваш маршрут, например:

get :foo, :bar => "bar"

В противном случае, предоставьте более подробную информацию о вашей проблеме.

Редактировать.

Вот решение (основное для вашего пост-обновления):

class ApplicationController < ActionController::Base
  def foo_path(foo, options = {})
    options.merge!(bar: foo.some_attribute)
    super
  end  
  helper_method :foo_path
end

Как показывают текущие ответы, вы не переопределяете хелпер rails (как определено где-то в app/helpers папку), но вспомогательный маршрут (как определено в config/routes.rb).

Вызов метода foo_path из представления работает, потому что сначала Rails просматривает все доступные вспомогательные методы приложения, а затем просматривает доступные вспомогательные методы маршрутизации.

Вызов метода из контроллера не работает, потому что Rails будет проходить только через доступные вспомогательные методы маршрутизации, а не через помощники маршрутизации.

Если вы хотите вызвать помощника приложения из контроллера, используйте это внутри вашего контроллера:

view_context.foo_path(...)

Это требует от вас предварительного view_context. за каждый звонок foo_path внутри каждого контроллера, так что это не идеальное решение, но оно должно работать.

Другие вопросы по тегам