问题描述
我正在尝试为这样的 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* 以防止命名问题,如果它们的连接来自其他链式命名范围.
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 上调用的,而不是在 User 上调用的.
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'
如何在 Scopes 模块中获得实际的 table_name?
How can I get actual table_name at Scopes module?
推荐答案
Rails 5, ApplicationRecord (希望对大家有帮助)
Rails 5, ApplicationRecord (Hope it helps others)
# app/models/concerns/not_older_than.rb
module NotOlderThan
extend ActiveSupport::Concern
included do
scope :not_older_than, -> (time, table = self.table_name){
where("#{table}.created_at >= ?", time.ago)
}
end
end
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include NotOlderThan
end
# app/models/user.rb
class User < ApplicationRecord
# Code
end
# Usage
User.not_older_than(1.week)
在 Rails 5 中,所有模型默认继承自 ApplicationRecord.如果您只想将此范围应用于特定的模型集,请仅将包含语句添加到这些模型类.这也适用于连接查询和链式作用域.
In Rails 5, all models are inherited from ApplicationRecord by default. If you wan to apply this scope for only particular set of models, add include statements only to those model classes. This works for join queries and chained scopes as well.
这篇关于破解 ActiveRecord:添加全局命名范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!