Определите метод для отлова a_method [] в классе - PullRequest
1 голос
/ 31 августа 2011

У меня много звонков на что-то вроде этого:

User.active[0..5]

Какой звонок:

class User
  def active
     (an ActiveRelation)
  end
end

Я пытаюсь сделать что-то подобное по соображениям производительности:

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

К сожалению, это не работает, есть идеи для реализации этого?

== РЕДАКТИРОВАТЬ

Еще чище:

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

Ответы [ 4 ]

4 голосов
/ 31 августа 2011

Вы можете иметь свой собственный специальный подкласс 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

Тогда User.active [5] должен работать как положено.

РЕДАКТИРОВАТЬ: Добавлена ​​информация об экземпляре. Вы можете посмотреть Base # scoped и Base # отношение для получения дополнительной информации

1 голос
/ 31 августа 2011

Вы можете сделать это так:

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
1 голос
/ 31 августа 2011

Можете ли вы попробовать его в качестве параметров вместо индексов массива? например:

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

(примечание: не проверялось ни на каких реальных ActiveRelations ...)

0 голосов
/ 31 августа 2011

Ну, вы определяете метод в неправильном классе.User.active[0..5] вызывает метод класса active в User и метод [] в любом классе User.active, который я возвращаю, я предполагаю, что он возвращает массив пользователей, а Array уже определилmethod [], так что об этом не стоит беспокоиться.

Вы можете запутаться, думая, что квадратные скобки - это своего рода скобка для передачи аргументов функции, в то время как они не являютсяПопробуйте это:

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

Итак, если вы хотите использовать find с массивами идентификаторов, вы можете просто использовать User[1,2,3].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...