How to dynamically generate association names?

扶醉桌前 提交于 2019-12-07 00:23:25

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

You can do this if you generate the methods dynamically. The Module.included method is provided for this purpose:

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

This gets triggered when the module is imported with include and allows you to create methods specifically tailored for that.

As a note you might want to use base.name.underscore.singularize for a more readable method name. By convention, method names should not have upper-case in them, especially not as the first character.

Conventional Rails type applications use a different approach, though, instead defining a class method that can be used to create these on-demand:

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

This would be used like this:

class ModelAsLikeArticle < ActiveRecord::Base
  extend MyModule

  has_comments
end

Since the method is not created until has_comments is called, you can safely extend ActiveRecord::Base and then insert the appropriate call in all the classes which require that functionality.

I think you might find what you need in the Rails Reflection class (http://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html), which, as the page says, allows you to interrogate ActiveRecord classes about their associations and aggregations.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!