Как я могу заставить named_scope в Rails возвращать одно значение вместо массива?

Я хочу написать named scope, чтобы получить запись с ее идентификатора.

Например, у меня есть модель под названием Event, и я хочу моделировать Event.find(id) с использованием named_scope для будущей гибкости.

Я использовал этот код в своей модели:

named_scope :from_id, lambda { |id| {:conditions => ['id= ?', id] } }

и я вызываю его из своего контроллера, например Event.from_id(id). Но моя проблема в том, что он возвращает массив объектов Event вместо одного объекта.

Таким образом, если я хочу получить имя события, я должен написать

event = Event.from_id(id)
event[0].name

в то время как я хочу

event = Event.from_id(id)
event.name

Я делаю что-то не так здесь?

Ответы

Ответ 1

Как упоминает Дэмиен, использование настраиваемой области просто для поиска по ID не рекомендуется. Но чтобы ответить на ваш вопрос:

Поиск записей с помощью named_scope всегда будет возвращать объект ActiveRecord::NamedScope::Scope, который ведет себя как массив. Если есть только одна запись, возвращаемая вашим запросом, вы можете использовать метод first для непосредственного получения объекта ActiveRecord, например:

event = Event.from_id(id).first
event.name # will work as you expect

Ответ 2

В этом случае я бы создал метод класса

def self.from_id(id)
  self.find(id).first
end

Другой пример:

class Invoice
  def self.number
    self.find(:first, 
      :select => "max(number) As last, max(number)+1 As next", 
      :conditions => "type = 'SalesOrder'")
  end
end

Такие методы лучше, чем named_scope. Вы можете вызвать Invoice.number.next, лучше, чем named_scope return Invoice.number[0].next.

Ответ 3

Здесь нет необходимости использовать область. Вы можете просто сделать Event.find_by_id id.
Разница между find и find_by_id заключается в том, что первый будет поднять ActiveRecordNotFoundException, если запись не существует. Второй возвращает только нуль.

Написание области для получения записи по этому идентификатору является очень плохим идентификатором, поскольку это то, что уже предусмотрено из-за рельсов.