黑客的ActiveRecord:添加全局命名范围全局、黑客、范围、ActiveRecord

2023-09-08 15:47:45 作者:爱过伤过

我想对ActiveRecord模型像这样的一包非常通用的命名范围的:

I am trying to have a pack of very generic named scopes for ActiveRecord models like this one:

module Scopes
  def self.included(base)
    base.class_eval do
      named_scope :not_older_than, lambda {|interval|
        {:conditions => ["#{table_name}.created_at >= ?", interval.ago]
      }
    end
  end
end
ActiveRecord::Base.send(:include, Scopes)

class User < ActiveRecord::Base
end

如果指定的范围应是一般情况下,我们需要指定* table_name的*为prevent命名问题,如果他们的就是加入了来自其他链接命名范围。

If the named scope should be general, we need to specify *table_name* to prevent naming problems if their is joins that came from other chained named scope.

现在的问题是,我们不能得到table_name的,因为它要求的ActiveRecord :: Base的而不是在用户。

The problem is that we can't get table_name because it is called on ActiveRecord::Base rather then on User.

User.not_older_than(1.week)

NoMethodError: undefined method `abstract_class?' for Object:Class
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2207:in `class_of_active_record_descendant'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1462:in `base_class'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1138:in `reset_table_name'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:1134:in `table_name'
from /home/bogdan/makabu/railsware/startwire/repository/lib/core_ext/active_record/base.rb:15:in `included'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:92:in `call'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:92:in `named_scope'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:97:in `call'
from /var/lib/gems/1.8/gems/activerecord-2.3.5/lib/active_record/named_scope.rb:97:in `not_older_than'

我怎样才能得到实际的table_name的在作用域模块?

How can I get actual table_name at Scopes module?

推荐答案

尝试使用#scoped方法中的ActiveRecord :: Base的类方法。这应该工作:

Try using the #scoped method inside a class method of ActiveRecord::Base. This should work:

module Scopes
  def self.included(base)
    base.class_eval do
      def self.not_older_than(interval)
        scoped(:conditions => ["#{table_name}.created_at > ?", interval.ago])
      end
    end
  end
end

ActiveRecord::Base.send(:include, Scopes)