破解 ActiveRecord:添加全局命名范围 [英] Hacking ActiveRecord: add global named scope

查看:11
本文介绍了破解 ActiveRecord:添加全局命名范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为这样的 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:添加全局命名范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆