如何动态生成关联名称?

我正在使用Ruby on Rails 3.2.2和Squeel gem。 我有以下语句,我试图在Mixin模块中重构my_squeel_query方法(因为它被我的许多模型使用):

 # Note: 'article_comment_associations' and 'model_as_like_article_comment_associations' # refer to database table names. class Article < ActiveRecord::Base def my_squeel_query commenters. .where{ article_comment_associations.article_id.eq(my{self.id}) & ... } end end class ModelAsLikeArticle < ActiveRecord::Base def my_squeel_query commenters. .where{ model_as_like_article_comment_associations.article_id.eq(my{self.id}) & ... } end end 

我的问题是我无法通过在Mixin模块中生成动态名称来重构article_comment_associationsmodel_as_like_article_comment_associations语句。 也就是说,如果那是一个String我可以通过使用类似"#{self.class.to_s.singularize}_comment_associations"的内容动态生成相关名称,如下所示:

 class Article < ActiveRecord::Base include MyModule end class ModelAsLikeArticle < ActiveRecord::Base include MyModule end module MyModule def my_squeel_query commenters. .where{ # Note: This code doesn't work. It is just an sample. "#{self.class.to_s.singularize}_comment_associations".article_id.eq(my{self.id}) & ... } end end 

但是,由于不是我的情况,我无法“构建”名称并使my_squeel_query在模型之间“共享”。

如何动态生成与Squeel gem相关的关联名称? 我应该考虑以另一种方式进行重构吗? 你有什么建议?

由于DSL是instance_evaled,你实际上可以这样说:

 def my_squeel_query base = self commenters. .where{ # Note: This code does work. Because it's awesome. __send__("#{base.class.to_s.singularize}_comment_associations"). article_id.eq(my{self.id}) } end 

如果动态生成方法,则可以执行此操作。 Module.included方法用于此目的:

 module ModuleAsLikeArticle def self.included(base) base.send(:define_method, "#{base.to_s.singularize}_comment_associations") do # ... end end end 

当使用include导入模块时会触发此操作,并允许您创建专门为其定制的方法。

作为注释,您可能希望使用base.name.underscore.singularize获取更易读的方法名称。 按照惯例,方法名称中不应包含大写字母,尤其不应作为第一个字符。

但是,常规Rails类型应用程序使用不同的方法,而是定义可用于按需创建这些类的方法:

 module ModuleAsLikeArticle def has_comments base.send(:define_method, "#{base.to_s.singularize}_comment_associations") do # ... end end end 

这将使用如下:

 class ModelAsLikeArticle < ActiveRecord::Base extend MyModule has_comments end 

由于在调用has_comments之前不会创建该方法,因此可以安全地扩展ActiveRecord::Base ,然后在需要该function的所有类中插入适当的调用。

我想你可能会在Rails Reflection类中找到你需要的东西(http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html),正如页面所说,它允许你查询有关他们的ActiveRecord类。协会和聚合。