Порядок сортировки по умолчанию для модели рельсов?

Я хотел бы указать порядок сортировки по умолчанию в моей модели.

Итак, когда я делаю .where() без указания .order(), он использует сортировку по умолчанию. Но если я укажу .order(), он переопределит значение по умолчанию.

Ответ 1

default_scope

Это работает для Rails 4 +:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

Для Rails 2.3, 3 вам это нужно:

default_scope order('created_at DESC')

Для Rails 2.x:

default_scope :order => 'created_at DESC'

Где created_at - это поле, в которое вы хотите выполнить сортировку по умолчанию.

Примечание: ASC - это код для восходящего и DESC для нисходящего (desc, НЕ dsc!).

scope

Как только вы привыкли к этому, вы также можете использовать scope:

class Book < ActiveRecord::Base
  scope :confirmed, :conditions => { :confirmed => true }
  scope :published, :conditions => { :published => true }
end

Для Rails 2 вам нужно named_scope.

:published область дает вам Book.published вместо Book.find(:published => true).

С Rails 3 вы можете "объединить" эти методы, объединив их с периодами между ними, поэтому с помощью вышеописанных областей теперь вы можете использовать Book.published.confirmed.

С помощью этого метода запрос фактически не выполняется до тех пор, пока фактические результаты не потребуются (ленивая оценка), поэтому 7 областей могут быть объединены вместе, но только приводят к 1 фактическому запросу базы данных, чтобы избежать проблем с производительностью при выполнении 7 отдельных запросов.

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

scope :recent_books, lambda 
  { |since_when| where("created_at >= ?", since_when) }
  # Note the `where` is making use of AREL syntax added in Rails 3.

Наконец, вы можете отключить область по умолчанию с помощью:

Book.with_exclusive_scope { find(:all) } 

или даже лучше:

Book.unscoped.all

который отключит любой фильтр (условия) или сортирует (упорядочивает).

Обратите внимание, что первая версия работает в Rails2 +, тогда как вторая (не зарегистрированная) предназначена только для Rails3 +


Так ... если вы думаете, хм, значит, это точно так же, как методы..., да, именно то, что эти области! Они похожи на def self.method_name ...code... end, но, как всегда, с рубинами, они - симпатичные маленькие синтаксические ярлыки (или "сахар" ), чтобы облегчить вам жизнь!

Фактически они являются методами уровня класса, поскольку они работают с 1 набором "всех" записей.

Их формат меняется, однако с рельсами 4 есть предупреждение об устаревании при использовании #scope без передачи вызываемого объекта. Например, область: красный, где (цвет: "красный" ) следует изменить до scope :red, -> { where(color: 'red') }.

В качестве побочного примечания при неправильном использовании по умолчанию _scope можно злоупотреблять/злоупотреблять.
В основном это касается того, когда он используется для таких действий, как where ограничение (фильтрация) выбора по умолчанию ( плохая идея по умолчанию), а не просто для упорядочивания результатов. Для выбора where просто используйте регулярные названные области. и добавьте эту область действия в запрос, например. Book.all.published где published - именованная область.

В заключение, области действительно отличные и помогут вам подтолкнуть модель к подходу DRYer "тонкий контроллер тонкой модели".

Ответ 2

Быстрое обновление Майкла, отличный ответ выше.

Для Rails 4.0+ вам нужно поместить свой вид в блок следующим образом:

class Book < ActiveRecord::Base
  default_scope { order('created_at DESC') }
end

Обратите внимание, что оператор порядка помещается в блок, обозначенный фигурными фигурными скобками.

Они изменили его, потому что было слишком легко передать что-то динамическое (например, текущее время). Это устраняет проблему, потому что блок оценивается во время выполнения. Если вы не используете блок, вы получите эту ошибку:

Поддержка вызова #default_scope без блока удаляется. Например, вместо default_scope where(color: 'red') используйте default_scope { where(color: 'red') }. (В качестве альтернативы вы можете просто переопределить self.default_scope.)

Как @Dan упоминает в своем комментарии ниже, вы можете сделать более рубиновый синтаксис следующим образом:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

или с несколькими столбцами:

class Book < ActiveRecord::Base
  default_scope { order({begin_date: :desc}, :name) }
end

Спасибо @Dan!