开发者

Define a method to catch a_method[] in a class

开发者 https://www.devze.com 2023-04-01 10:42 出处:网络
I have a lots of call to something like this : Use开发者_如何学JAVAr.active[0..5] Which call : class User

I have a lots of call to something like this :

Use开发者_如何学JAVAr.active[0..5]

Which call :

class User
  def active
     (an ActiveRelation)
  end
end

I am trying to do something like this for performance reasons :

class User
  def active[limit]
     (an ActiveRelation).limit(limit.to_a.size)
  end
end

Unfortunately it doesn't work, any ideas to implement this ?

== EDIT

More cleaner :

class RelationWithLimit < ActiveRecord::Relation
  def [] selector
    case selector
    when Integer
      self.offset(selector).limit(1)
    when Range
      self.offset(selector.to_a[0]).limit(selector.to_a.size)
    end
  end
end

class ActiveRecord::Base
  private 
    def self.relation #:nodoc:
      @relation ||= RelationWithLimit.new(self, arel_table)
      finder_needs_type_condition? ? @relation.where(type_condition) : @relation
    end
end


You could have your own special subclass of ActiveRelation

class UserReturnRelation < ActiveRecord::Relation
  def [] lim
    self.limit lim
  end
end

class User
  def active
     # Without knowing exactly what relation you are using
     # One way to instantiate the UserReturnRelation for just this call
     UserReturnRelation.new(self, arel_table).where("state = active")
  end
end

Then User.active[5] should work as expected.

EDIT: Added instantiation info. You may want to look at Base#scoped and Base#relation for more info


Can you try it as params instead of array-indices? eg:

class User
  def active(the_limit)
     (an ActiveRelation).limit(the_limit)
  end
end
User.active(5)

(note: not tested on any actual ActiveRelations...)


You can do it like this:

class User
  def active
    Limiter.new((an ActiveRelation))
  end

  class Limiter
    def initialize(relation)
      @relation = relation
    end

    def method_missing(method, *arguments, &block)
      @relation.send(method, *arguments, &block)
    end

    def respond_to?(method, include_private = false)
      @relation.respond_to?(method, include_private) || super
    end

    def [](value)
      offset = value.to_a.first
      limit = value.to_a.last - offset
      @relation.offset(offset).limit(limit)
    end
  end
end


Well, you are defining the method in the wrong class. User.active[0..5] calls the class method active in User and the method [] in whatever class User.active is returning, I'll assume that it is returning an array of users, and Array has already defined the method [] so no worries about that.

You may be getting confused thinking that brackets are some kind of parenthesis for passing arguments to a function while they're not. Try this:

class User
  class << self
    def [](values)
      self.find(values)
    end
  end
end

So, if you wanna use find with an arrays of ids, you may just use User[1,2,3].

0

精彩评论

暂无评论...
验证码 换一张
取 消