Порядок сортировки по умолчанию для модели рельсов? - PullRequest
240 голосов
/ 03 августа 2010

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

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

Ответы [ 3 ]

512 голосов
/ 10 апреля 2011

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 отдельных запросов.

Вы можете использовать переданный параметр, такой как date или 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 +


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

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

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

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

В заключение, области видимости действительно хороши и помогают вам перенести вещи в модель для подхода DRYer «тонкая модель с толстой моделью».

108 голосов
/ 02 мая 2014

Быстрое обновление превосходного ответа Майкла выше.

Для 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

Спасибо @ Дан !

6 голосов
/ 03 августа 2010

Вы можете использовать default_scope для реализации порядка сортировки по умолчанию http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html

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