1

我正在使用 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_associations和声明。model_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 相关的关联名称?我应该考虑以另一种方式重构吗?你有什么建议?

4

3 回答 3

1

如果您动态生成方法,则可以执行此操作。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,然后在所有需要该功能的类中插入适当的调用。

于 2012-09-26T16:39:10.347 回答
1

由于 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
于 2012-09-26T23:13:48.460 回答
0

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

于 2012-09-26T16:09:34.630 回答