Сортировка Rails по виртуальному атрибуту, сгенерированному из метода модели

Меня интересует замечательная функция, которая может очень помочь для сортировки по атрибутам модели или по виртуальным атрибутам модели.

У меня есть модель под названием Box с некоторыми атрибутами. Я показываю в своем индексном представлении список этих полей с атрибутами и статусом. Этот статус немного особенный, прежде чем он сгенерирован и не записан в моей базе данных (мы говорим о статусе в реальном времени, нет никакого интереса его записывать).

Я застрял с проблемой сортировки по этому статусу.

Моя идея заключается в следующем:

#Box.rb
attr_accessor :status

def generate_status
  self.status = "awesome status" 
end

def status
  @status
end

def status=(val)
  @status = val
end

И я хотел бы получить доступ к этой информации на моем контроллере

#BoxesController.rb
@boxes = Box.all #With my sort by virtual attribute status

Я действительно не хочу делать (до того, как узнаю, как сортировать виртуальный атрибут):

@boxes = Box.all
@boxes.each do |b|
  b.status = b.generate_status
end

Наконец, если это возможно, я обобщу это на все перечисленные методы моей модели через Concern, я думаю. Но для начала этой работы мне нужно знать, можно ли сортировать по виртуальному атрибуту

Изменить:

Теперь я пытаюсь таким образом в области:

#In a Concern included in my model
(["status"] rescue []).each do |method|
  scope "sort_by_#{method}", ->(order){
    if order.equal?("asc")
      self.where(nil).sort!{|a,b| a.send(method) <=> b.send(method)}
    else
      self.where(nil).sort!{|a,b| b.send(method) <=> a.send(method)}
    end
  }
end

Нет никакой ошибки, но мои элементы не отсортированы.

Обратите внимание, что я назвал ["status"] временным, потому что в настоящее время я пытаюсь получить доступ к этой переменной, объявленной в моей модели (где моя проблема включена)

Спасибо за помощь!


person brcebn    schedule 21.11.2014    source источник


Ответы (1)


Невозможно отсортировать по виртуальному атрибуту с помощью ActiveRecord, однако мы можем использовать sort_by! для результата. http://www.ruby-doc.org/core-2.1.5/Array.html#method-i-sort_by-21

@boxes.sort_by! { |a,b| a.status <=> b.status }

Чтобы автоматически установить статус, вы можете использовать обратный вызов after_find.

#Box.rb
attr_accessor :status

after_find :generate_status

def generate_status
    self.status = 'awesome status`
end
person KPheasey    schedule 21.11.2014
comment
sort_by не работает. У меня эта ошибка NoMethodError: undefined method status' for nil:NilClass. Но Box.all.map{|b| b.status} работает. Кажется, что переменная b в sort_by равна нулю. - person brcebn; 24.11.2014
comment
Вы уверены, что массив содержит как минимум 2 элемента? - person KPheasey; 03.12.2014