我在Rails引擎gem的上下文中遇到了Ruby类(常量)查找的问题。
我有一个宝石MyGem,它是一个Rails引擎。它定义了预期被MainApp覆盖的非命名空间模型,其中包括gem和命名空间模块,这些模块包含在gem和main_app的模型中,以便以DRY方式定义可重用代码。
以下是一个示例代码结构:
两种模式
# in /app/models/user.rb
class User < ActiveRecord::Base
include MyGem::User::CommonExt
end
# in /app/models/comment.rb
class Comment < ActiveRecord::Base
include MyGem::Comment::CommonExt
end
他们的两个模块
# in /app/models/concerns/my_gem/user/common_ext.rb
module MyGem::User::CommonExt
def load_comment(id)
return Comment.find(id)
end
end
# in /app/models/concerns/my_gem/comment/common_ext.rb
module MyGem::Comment::CommonExt
def load_user(id)
return User.find(id)
end
end
现在,如果我打电话
User.new.load_comment(1)
我得到undefined method #find for MyGem::Comment::Module
我想我理解为什么会这样 - 在#load_comment
定义的上下文中,MyGem
下的命名空间,Comment
常量查找返回MyGem :: Comment,而不是更多遥远的::Comment
我不希望在::
之前添加每个模型实例
是否有文件结构,模型/类定义或配置更改我可以用来调用Comment返回模型Comment,而不是MyGem :: Comment模块?
答案 0 :(得分:0)
在这种情况下,我会使用继承而不是mixin。
因此,在您的gem /引擎中,您可以定义与此类似的公共类:
module MyGem
module Common
class Base < ActiveRecord::Base
# common functionality goes here
def load(record_type, id)
record_type.find(id)
end
end
end
end
然后在您的main_app
代码中
class User < MyGem::Common::Base
...
end
现在你可以这样做:
User.new.load(Comment, 1)
这违反了Law of Demeter,但希望它说明了这一点。
这样做是干的,并且还有一个额外的好处,就是它可以防止你的宝石必须知道超出它自己范围的类。