Search code examples
ruby-on-railsrubyruby-on-rails-3refactoringsqueel

How to dynamically generate association names?


I am using Ruby on Rails 3.2.2 and the Squeel gem. I have following statements and I am trying to refactoring the my_squeel_query method in a Mixin module (since it is used by many of my models):

# 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

My problem is that I can not refactoring article_comment_associations and model_as_like_article_comment_associations statements by generating a dynamic name in the Mixin module. That is, if that was a String I could dynamically generate the related name by using something like "#{self.class.to_s.singularize}_comment_associations" as the following:

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

But, since it is not my case, I cannot "build" the name and make the my_squeel_query to be "shared" across models.

How can I dynamically generate association names related to the Squeel gem? Should I think to refactoring in another way? What do you advice about?


Solution

  • Since the DSL is instance_evaled, you can actually say something like:

    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