Порядок сортування за замовчуванням для моделі рейок?


255

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

Так що коли я роблю .where()без вказівки, .order()він використовує сортування за замовчуванням. Але якщо я вказую .order(), це перевизначає за замовчуванням.

Відповіді:


544

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')

Для рейок 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

Для Рейки 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 до "жирої моделі тонкого контролера".


1
Будь ласка , зверніть увагу попередження Дейва Томаса про використання default_scope перед його використанням , як описано в цьому пості: pragdave.blogs.pragprog.com/pragdave/2012/03 / ...
Рето

3
хіба це не було б безпечніше зробити default_scope { order("#{table_name}.created_at DESC") }?
cyrilchampier

37
Рейки 4:default_scope { order(created_at: :desc) }
Маркус

2
Принаймні, 4.2.6схоже на сортування за updated_atні created_at.
Айн Тохрі

2
@AinTohvri має рацію. Це мене просто здивувало в Rails 4.2. Чому сортувати updated_atза замовчуванням? : - |
шістдесят біт

112

Швидке оновлення чудової відповіді Майкла вище.

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


28
У рейках 4 це також можна записати так, default_scope { order(created_at: :desc) }ніби, як і я, ви намагаєтеся мінімізувати синтаксис sql в рейках. <br/> Якщо у вас є кілька стовпців, які потрібно замовити, і ви хочете використовувати новий синтаксис, можливо, вам знадобиться обгортати desc стовпчиків у вусах, як цеdefault_scope { order({begin_date: :desc}, :name) }
День

1
@Dan - Ваш коментар не тільки усуває SQL, але є більш рубіським синтаксисом.
B Сьоме

6

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


6
Посилання працює , але там немає нічого про default_scopeна цій сторінці, тому що він був перероблений з ActiveRecord::Baseв ActiveRecord::Scoping::Default::ClassMethods( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default / ... )
Daniel Rikowski
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.