22

私は作業中にRoRプロジェクトを手に入れました。これが私のモデルの該当するセクションです。

ホーム

has_many :communities, :through => :availabilities
has_many :availabilities, :order => "price ASC"

コミュニティ

has_many :homes, :through => :availabilities
has_many :availabilities

可用性

belongs_to :home
belongs_to :community

データベースの「空室状況」テーブルには、追加のデータ列「価格」があります。

だから今私は呼び出すことができます

@home.availabilities.each do |a|
  a.community.name
  a.price

そして私が望むように価格順に並べられた空室状況データを取り戻しなさい。私の質問はこれです:

によって自動的に家を注文する方法はありますかavaliabilities.first.price(最初=最低)?多分何かdefault_scope :order

5 답변


25

私は使用を避けることをお勧めしますdefault_scope特に他のテーブルの価格のようなものでは。そのテーブルを使用するたびに、結合と順序付けが行われ、複雑なクエリで奇妙な結果が生じる可能性があり、とにかくクエリが遅くなります。

それ自身の範囲に問題はありません、それはより単純で、そしてより明確です、あなたはそれを同じくらい単純にすることができます:

scope :ordered, -> { includes(:availabilities).order('availabilities.price') }

シモンズ:にインデックスを追加することを忘れないでくださいprice


  • あなたは使う必要がありますかincludes参加する代わりに? - Jwan622
  • 次第に、@ TeWuは彼の答えの違いを説明するのに素晴らしい仕事をしている。特にTom Dallimoreのブログへのリンクは最高です。 - ecoologic

21

から助けを借りてそれを考え出したこの関連記事

私は、注文をHomeモデルからAvailabilityモデルに移動しました。

可用性

default_scope :order => "price ASC"

それから私は家のモデルに空室状況をロードして価格でソートしたがっています:

ホーム

default_scope :include => :availabilities, :order => "availabilities.price ASC"


8

エコロジー回答

scope :ordered, -> { includes(:availabilities).order('availabilities.price') }

素晴らしいですが、それは言及されるべきですincludes可能性があり、場合によっては次のように置き換えられます。joinsどちらも最適なユースケースがあります

実用的な観点からは、主に2つの違いがあります。

  1. includes関連レコードをロードします。この場合Availability記録。joins関連付けられているレコードをロードしないでください。だからあなたは使うべきですincludes結合モデルのデータを使用したい場合表示priceどこかに。一方、joins結合モデルのデータをクエリ内でのみ使用する場合は、これを使用してください。にORDER BYまたはWHERE条項

  2. includesすべてのレコードをロードしますjoins結合モデルが関連付けられているレコードのみをロードします。だからOPの場合、Home.includes(:availabilities)一方、すべての家に荷を積みますHome.joins(:availabilities)少なくとも1つの可用性に関連付けられている住宅のみをロードします。

また見なさいこの質問


2

Rails 5.2以降では、orderメソッドに文字列パラメータを渡すときに非推奨の警告が表示されることがあります。

非推奨警告:危険なクエリメソッド(引数が生のSQLとして使用されているメソッド)が、属性以外の引数で呼び出されました: "table.column"。 Rails 6.0では、属性以外の引数は許可されません。このメソッドは、リクエストパラメータやモデル属性などのユーザー指定の値で呼び出さないでください。

これを解決するために、あなたは使うことができますArel.sql()

scope :ordered, -> {
  includes(:availabilities).order(Arel.sql('availabilities.price'))
}


1

これを達成するためのもう一つの方法:

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price]) }

指定することもできますASCとの方向

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price].asc) }

DESC

scope :ordered, -> { includes(:availabilities).order(Availability.arel_table[:price].desc) }

を使うarel_tableActiveRecordモデルは、テーブル名が変更されたときにシナリオを回避するようにします(ただし、めったに起こりません)。

追加するのが良いことに注意してくださいmain_table#id確定ソートのため。

そのため、最終版は次のようになります。

scope :ordered, -> {
  includes(:availabilities).
    order(Availability.arel_table[:price].asc, order(Home.arel_table[:id].asc)
}

リンクされた質問


関連する質問

最近の質問