Railsモデルのデフォルトのソート順?


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

Rails 2.xの場合:

default_scope :order => 'created_at DESC'

created_atデフォルトのソートを実行するフィールドはどこですか。

注:ASCは昇順で使用するコードで、DESCは降順(descNOT 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 +で動作しますが、2番目のバージョン(対象範囲外)はRails3 +専用です。


だから ...あなたが考えているなら、うーん、これらはメソッドと同じです...そうです、そう、まさにこれらのスコープとは!
彼らは持っているようなものですdef self.method_name ...code... endが、いつものようにルビーでは、あなたにとって物事をより簡単にするための素敵な小さな構文上のショートカット(または「砂糖」)です!

実際、これらは1セットの「すべて」のレコードを操作するため、クラスレベルのメソッドです。

ただし、それらの形式は変更されていますが、rails 4では、呼び出し可能なオブジェクトを渡さずに#scopeを使用すると非推奨の警告が表示されます。たとえば、scope:red、where(color: 'red')はに変更する必要がありますscope :red, -> { where(color: 'red') }

補足として、誤って使用すると、デフォルトの _scopeが誤用/乱用される可能性があります
これは、それがのようなアクションのために使用されますときについて主にあるwhereの制限(フィルタリング)、デフォルトの選択(悪いアイデアだけ発注の結果を得るために使用されるのではなく、デフォルトの場合)。
以下のためwhereの選択、普通の名前のスコープを使用しています。そして、そのスコープをクエリに追加します。たとえばBook.all.publishedpublishedは名前付きスコープです。

結論として、スコープは本当に素晴らしいものであり、「脂肪モデルシンコントローラー」のDRYerアプローチのモデルに物事を押し上げるのに役立ちます。


1
:この記事で説明したように、それを使用する前に、default_scopeの使用についてのデイブ・トーマスの警告をご検討くださいpragdave.blogs.pragprog.com/pragdave/2012/03/...
レト

3
それを行う方が安全ではないdefault_scope { order("#{table_name}.created_at DESC") }でしょうか?
シリルチャンピア2014年

37
Rails 4:default_scope { order(created_at: :desc) }
Marcus 14

2
少なくとも4.2.6ソートしupdated_atないようcreated_atです。
Ain Tohvri

2
@AinTohvriは正しいです。これは、Rails 4.2で驚きました。なぜupdated_atデフォルトでソートするのですか?:-|
sixty4bit 2017年

112

上記のマイケルの優れた答えの簡単な更新。

Rails 4.0以降の場合は、次のようにソートをブロックに入れる必要があります。

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

orderステートメントは、中括弧で示されたブロックに配置されていることに注意してください。

動的なもの(現在の時間など)を渡すのは簡単すぎるため、変更されました。これにより、ブロックが実行時に評価されるため、問題が解消されます。ブロックを使用しないと、次のエラーが発生します。

ブロックなしで#default_scopeを呼び出すサポートは削除されました。たとえばの代わりにdefault_scope where(color: 'red')を使用してくださいdefault_scope { where(color: 'red') }。(あるいは、単にself.default_scopeを再定義することもできます。)

以下のよう@Danは以下の彼のコメントに言及し、あなたはこのような、よりrubyish構文を行うことができます。

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
rails 4では、これはdefault_scope { order(created_at: :desc) }私のように、railsでSQL構文を最小限に抑えようとすることもできます。<br/>複数の列を並べ替えて新しい構文を使用したい場合は、descをラップする必要がある場合があります。このような口ひげのある列default_scope { order({begin_date: :desc}, :name) }
Dan

1
@Dan-コメントはSQLを排除するだけでなく、よりルビーな構文です。
Bセブン

6

default_scopeを使用して、デフォルトのソート順を実装できます http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html


6
リンクが機能していますが、については何もありませんdefault_scope、それはからリファクタリングされているので、そのページには、ActiveRecord::BaseActiveRecord::Scoping::Default::ClassMethodsapi.rubyonrails.org/classes/ActiveRecord/Scoping/Default/...
ダニエルRikowski
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.