Rails Rails routing and namespaced models

kikyous · 2017年08月01日 · 最后由 jasl 回复于 2017年08月06日 · 1700 次阅读

在一个比较复杂的 rails 程序里,如果你使用 namespace 来进行模块化:

class Admin::Company < ApplicationRecord
end
class Admin::Custom < ApplicationRecord
end
namespace :admin do
  resources :companies do
    resources :customs
  end
end

在 form_for 时就会遇到麻烦

<%= form_for([@company, @custom]) do |f| %>
<% end %>

这样 rails 会去找一个不存在的路由然后报错: undefined method admin_company_admin_customs_path

这样也会报错

<%= form_for([:admin, @company, @custom]) do |f| %>
<% end %>

undefined method admin_admin_company_admin_customs_path

我之前的解决方法都是给 form_for 传入 url 参数,手动指定 path,但是这样又要判断是 new 还是 edit

今天终于找到了解决方法 在 admin.rb 里定义 use_relative_model_naming?

module Admin
  def self.use_relative_model_naming?
    true
  end
end

然后

<%= form_for([:admin, @company, @custom]) do |f| %>
<% end %>

一切又回归优雅了😀

https://coderwall.com/p/heed_q/rails-routing-and-namespaced-models

记得碰过这个坑,后来是通过重写类方法 model_name 解决的。

module Admin
  class BaseModel < ActiveRecord::Base
    self.abstract_class = true

    def self.model_name
      ActiveModel::Name.new(self, nil, name.demodulize)
    end 

  end 
end
prothro 回复

这种方法只能解决模型和控制器在同一个 module 下的,如果不同的话,还是要这样覆写 model_name

prothro 回复

重写 model_name 会有副作用吧

jasl 回复

这个应该和控制器的 module 没关系吧。

kikyous 回复

有一些变化

之前:

irb(main):001:0> Admin::Category.model_name
=> #<ActiveModel::Name:0x0055cfa8459ac0 @name="Admin::Category", @klass=Admin::Category, @singular="admin_category", @plural="admin_categories", @element="category", @human="Category", @collection="admin/categories", @param_key="admin_category", @i18n_key=:"admin/category", @route_key="admin_categories", @singular_route_key="admin_category">

之后:

irb(main):001:0> Admin::Category.model_name
=> #<ActiveModel::Name:0x0055cfa8459200 @name="Category", @klass=Admin::Category, @singular="category", @plural="categories", @element="category", @human="Category", @collection="categories", @param_key="category", @i18n_key=:category, @route_key="categories", @singular_route_key="category">

目前发现的副作用是:@route_key, 使写 local 文件可以省去 module 的名字 比如:

models:
  admin/category: 类别

# 变成
models:
  category 类别
prothro 回复

那天开会去了。。。回来翻了下源码,没注意是要加到 module 上的,简单来说就是加了以后,model_name 就把 namespace 设置成 nil,于是就等同于

def self.model_name
  ActiveModel::Name.new(self, nil, name.demodulize)
end 

这个 hack 了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号