Rails url_for 和命名空间模型

Posted

技术标签:

【中文标题】Rails url_for 和命名空间模型【英文标题】:Rails url_for and namespaced models 【发布时间】:2011-05-23 05:04:12 【问题描述】:

在 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 中的模块并为url_for(@user) 返回user_path 而不是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/usersapp/controllers/m/users_controller.rbapp/controllers/users_controller.rb;除了模型M::User 之外,您还需要删除对模块M 的引用。

最后,这里的目标是命名模型而不是视图和控制器。使用 esads 解决方案,模块M(包含User)被明确告知不要出现在路由中。因此,实际上,M 被删除,只剩下User

用户模型现在可以位于app/views/models/m/user.rb,用户控制器位于app/views/controllers/users_controller.rb,视图可以在app/views/users中找到。

【问题讨论】:

【参考方案1】:

只需在包含模块中定义use_relative_model_naming? 以避免在生成的路由名称前加上前缀:

module M
  def self.use_relative_model_naming?
    true
  end
end

【讨论】:

这是金!解决了 OP 的要求(以及我在寻找什么)谢谢 这个方法应该是 Rails API 中记录的第一个方法! 对自己(和其他人)的注意:这必须在模块中,即命名空间本身,而不是在类中。【参考方案2】:

使用

namespace "blah" do
  resources :thing
end

然后路线将被适当地命名。

rake routes

查看所有路线

【讨论】:

谢谢,我试过了,但它并没有解决问题:虽然 url_for 被告知模型命名空间,但路由(控制器)将适应使用相同的命名空间——这不是我的需要。因此:是否可以设置路由以使用位于不同命名空间中的模型和控制器?换句话说,有没有一种方法可以影响 url_for 给定模型实例的行为,而无需触及控制器路由?例如,模型 M::User 将定义在 app/models/m/user.rb 中,而控制器将定义在 app/controllers/user_controller.rb 中。 另外,如果它不是 RESTFul 资源,你会怎么做?我有这个问题,我正在处理的控制器不能被硬塞到资源中。 resources :things do (new line) get "foo" => "controller#action". 这不是正确的答案,请参阅我上面的编辑。要求是这样的:将模型放入模块中,没有命名空间视图和控制器。在您的解决方案中,模型、视图和控制器都必须命名空间。【参考方案3】:

指定路由上的模块

resources :users, :module => "m"

或者使用作用域来做

scope :module => "m" do
  resources :users
end

【讨论】:

完美运行!谢谢:)【参考方案4】:

在我的例子中,我重写了 application_helper.rb 文件中的 url_for 方法,以在我的命名空间 :mkp 的所有路由上添加 :network 参数。

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

【讨论】:

以上是关于Rails url_for 和命名空间模型的主要内容,如果未能解决你的问题,请参考以下文章

Rails 中的命名空间模型:联合的状态是啥?

命名空间模型中的 Rails 关联

Rails 4:在没有命名空间模型的子路径中组织 Rails 模型?

删除存在于另一个命名空间 rails 中的模型

Rails 使用同一命名空间中的模型作为 belongs_to 引用,如何从外部引用模型

Rails 命名空间与嵌套资源