Rails url_for и модели с пространством имен

Возможно ли в Rails размещать модели пространств имен в модулях и при этом получать правильное поведение от url_for?

Например, здесь url_for работает как положено:

# app/models/user.rb
class User < ActiveRecord::Base
end

# config/routes.rb
resources :users

# app/views/users/index.html.haml
= url_for(@user)    # /users/1

Тогда как после помещения модели User в модуль url_for жалуется на неопределенный метод m_user_path:

# app/models/m/user.rb
module M
  class User < ActiveRecord::Base
  end
end

# config/routes.rb
resources :users

# app/views/users/index.html.haml
= url_for(@user)    # undefined method 'm_users_path'

Возможно ли, чтобы url_for игнорировал модуль в M::User и возвращал user_path для url_for(@user) вместо m_user_path?

ОБНОВЛЕНИЕ

Итак, спустя почти 5 лет, вот решение, благодаря esad. Это было протестировано в Rails 4.2.

# app/models/m/user.rb
module M
  class User < ActiveRecord::Base
  end
end

# app/models/m.rb
module M
  def self.use_relative_model_naming?
    true
  end
  def self.table_name_prefix
    'm_'
  end
end

# config/routes.rb
resources :users

# app/views/users/index.html.haml
= url_for(@user)    # /users/1

Примечание: при создании модели, представления и контроллера с помощью bin/rails g scaffold m/user представления и контроллер также будут иметь пространство имен. Вам нужно переместить app/views/m/users в app/views/users и app/controllers/m/users_controller.rb в app/controllers/users_controller.rb; также нужно убрать ссылки на модуль M везде, кроме модели M::User.

Наконец, целью здесь были модели пространств имен, а не представления и контроллеры. В решении esads модулю M (содержащему User) явно приказано не появляться в маршрутах. Таким образом, фактически M удаляется и остается только User.

Пользовательская модель теперь может находиться в app/views/models/m/user.rb, пользовательский контроллер находится в app/views/controllers/users_controller.rb, а представления можно найти в app/views/users.


person sebastian    schedule 10.12.2010    source источник


Ответы (4)


Просто определите use_relative_model_naming? в содержащем модуле, чтобы избежать префикса сгенерированных имен маршрутов:

module M
  def self.use_relative_model_naming?
    true
  end
end
person esad    schedule 22.11.2012
comment
Это золото! Решает именно то, о чем спрашивал ОП (и что я искал). Спасибо. - person Ivar; 21.08.2013
comment
Этот метод должен быть первым, задокументированным в Rails API! - person olhor; 13.12.2014
comment
Примечание для себя (и других): это должно быть в модуле, то есть в самом пространстве имен, а не в классе. - person bovender; 28.07.2017

Использовать

namespace "blah" do
  resources :thing
end

Тогда маршруты будут называться соответственно.

rake routes

Для просмотра всех маршрутов

person sethvargo    schedule 10.12.2010
comment
Спасибо, я пробовал это, но это не решает проблему: хотя url_for получает информацию о пространстве имен модели, маршруты (контроллеры) будут адаптированы для использования того же пространства имен, что мне не нужно. Таким образом: можно ли настроить маршруты для использования моделей и контроллеров, живущих в разных пространствах имен? Другими словами, есть ли способ повлиять на поведение url_for данного экземпляра модели, не касаясь маршрутов контроллера? Например, модель M::User будет определена в app/models/m/user.rb, тогда как контроллер будет определен в app/controllers/user_controller.rb. - person sebastian; 12.12.2010
comment
Кроме того, что вы делаете, если это не ресурс RESTFul? У меня есть эта проблема, и контроллер, с которым я имею дело, не может быть подключен к ресурсу. - person Ibrahim; 24.12.2010
comment
ресурсы :things do (новая строка) get foo =› controller#action. - person sethvargo; 25.12.2010
comment
Это неправильный ответ, см. мое редактирование выше. Требовалось следующее: поместить модель внутрь модуля, без представления пространств имен и контроллеров. В вашем решении и модель, и представления, и контроллеры должны иметь пространство имен. - person sebastian; 07.05.2015

Указать модуль на маршруте

resources :users, :module => "m"

или используйте область видимости, чтобы сделать это

scope :module => "m" do
  resources :users
end
person stevehodgkiss    schedule 04.01.2011
comment
Работает отлично! Спасибо :) - person Volte; 15.03.2013

В моем случае я переопределил метод url_for в моем файле application_helper.rb, чтобы добавить параметр :network на все маршруты из моего пространства имен :mkp.

module ApplicationHelper
  def url_for(options = {})
    if options.is_a?(Hash) && options.has_key?(:controller)
      if options[:network].nil? && options[:controller].match(/^mkp\//).present?
        options[:network] = @network.downcase
      end
    end
    super(options)
  end
end
person mjlescano    schedule 27.03.2013