Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use common ActiveRecord scopes(scope) with module in Rails?

In rails3, I make same scopes in model. for example

class Common < ActiveRecord::Base
  scope :recent    , order('created_at DESC')
  scope :before_at , lambda{|at| where("created_at < ?" , at) }
  scope :after_at  , lambda{|at| where("created_at > ?" , at) }
end

I want to split common scopes to module in lib. So I try like this one.

module ScopeExtension
  module Timestamps
    def self.included(base)
      base.send :extend, ClassMethods
    end

    module ClassMethods
      scope :recent      , lambda{order('created_at DESC')}
      scope :before_at   , lambda{|at| where("created_at < ?" , at) }
      scope :after_at    , lambda{|at| where("created_at > ?" , at) }
    end
end

and I write this one

class Common < ActiveRecord::Base
  include ScopeExtension::Timestamps
end

But Rails show this error.

undefined method `scope' for ScopeExtension::Timestamps::ClassMethods:Module

(I didn't forget auto loading library)

How can I easily reuse common scope feature in active record?

I guess this problem to relate loading sequence. But I don't have any idea to solve. Please hint me.

like image 698
neocoin Avatar asked Aug 28 '11 19:08

neocoin


2 Answers

I solved this calling the scope on self.included(class):

module Timestamps
   def self.included(k)
      k.scope :created_yesterday, k.where("created_at" => Date.yesterday.beginning_of_day..Date.yesterday.end_of_day)
      k.scope :updated_yesterday, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
      k.scope :created_today, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
      k.scope :updated_today, k.where("created_at" => Date.today.beginning_of_day..Date.today.end_of_day)
   end
end
like image 139
Estevão Mascarenhas Avatar answered Nov 07 '22 18:11

Estevão Mascarenhas


In Rails 3 there's no difference between a declared scope and a class method that returns an ActiveRecord::Relation, so it can be more elegant to use a mixin module:

class MyClass < ActiveRecord::Base
  extend ScopeExtension::Timestamps
end

module ScopeExtension
  module Timestamps
    def recent
      order('created_at DESC')
    end

    def before_at(at)
      where('created_at < ?' , at)
    end

    def after_at(at)
      where('created_at > ?' , at)
    end
  end
end

MyClass.after_at(2.days.ago).before_at(1.hour.ago).recent
like image 37
m1foley Avatar answered Nov 07 '22 19:11

m1foley