我有一个命名空间的Post控制器,如下所示
class Admin::Blog::PostsController < Admin::BaseController
end
和命名空间模型如下。
class Blog::Post < ActiveRecord::Base
end
但是当我尝试在帖子控制器的索引动作中访问模型时,如下所示
def index
@posts = Blog::Post.where(:foo_id => params[:id]).paginate(:page => params[:page], :per_page => 20)
end
我收到以下错误
LoadError at /admin/blog/posts
Expected/app/models/blog/post.rb to define Post
但是,当我将模型从Blog :: Post移动到Admin :: Blog :: Post命名空间时,它就可以了。
我对此感到困惑,无法了解这一点。 是否需要Controller和Model应存在于同一名称空间中?
以下是routes.rb
的摘录namespace :admin do
namespace :blog do
resources :posts
resources :categories
end
end
博客模块代码段
module Blog
def self.table_name_prefix
'blog_'
end
end
预加载控制器和模型
config.autoload_paths += Dir["#{Rails.root}/app/models/**/**"]
config.autoload_paths += Dir["#{Rails.root}/app/controllers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/helpers/**/**"]
config.autoload_paths += Dir["#{config.root}/app/tags/**/**"]
config.autoload_paths += %W[ #{Rails.root}/app/extensions #{Rails.root}/app/modules #{Rails.root}/app/drops #{Rails.root}/app/filters #{Rails.root}/app/mailers ]
答案 0 :(得分:0)
这可能是由rails的自动加载器引起的。这样做时:
module Foo
class Bar
end
end
然后尝试使用Foo::Bar
,自动加载器首先尝试找到app/models/foo/bar.rb
。该文件已加载,此处定义了module Foo
(虽然该模块仅包含Bar
),因此自动加载器永远不会尝试加载app/models/foo.rb
。
这应该只在开发模式下进行,因为在生产模式下,所有文件在启动时都是require
。
AFAIK有两种解决方法:
需要模块
使用require_dependency
:
require_dependency 'foo'
module Foo
class Bar
end
end
这是恕我直言的正确解决方案,因为它不会破坏常量查找,但它也有点烦人,因为你必须在每个命名空间文件的顶部添加require语句。
创建自定义有效记录库
此解决方案不依赖于自动加载。将模型设置为从以下内容继承,而不是直接从ActiveRecord::Base
继承:
class CustomActiveRecordBase < ActiveRecord::Base
self.abstract_class = true
# If no table name prefix has been defined, include the namespace/module as
# table name prefix, e.g., Blog:: -> blog_
def self.table_name
# If a table_name_prefix has been defined, follow default behaviour
return super if full_table_name_prefix.present?
# Find the prefix, e.g., Blog::Post -> 'blog', User -> ''
prefix = model_name.name.deconstantize.underscore
# If no prefix, follow default behaviour
return super unless prefix.present?
# Otherwise add the prefix with an underscore
"#{prefix}_#{super}"
end
end
然后,无需在self.table_name_prefix
中定义blog.rb
。
这个可以全部通过猴子修补ActiveRecord::Base
完成,但这会干扰其他类,例如ActiveRecord::SchemaMigration
,它没有表前缀。< / p>
注意:
这个bug似乎已经在rails 4中解决了。我在rails 3上使用了第二个解决方法,但是我试图重现rails 4中的bug并且它不再出现了。我认为他们修改了自动加载器的工作方式...有关详细信息,请参阅the rails guides on autoloading and reloading constants