我的作品中有一个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
的东西?
答案 0 :(得分:29)
我建议避免使用default_scope
,尤其是在另一张桌子上的价格等方面。每次您使用该表时,都会发生加入和排序,可能会在复杂查询中产生奇怪的结果,并且无论如何都会使查询变慢。
它的范围没有任何问题,它更简单,而且更清晰,你可以把它简单化为:
scope :ordered, -> { includes(:availabilities).order('availabilities.price') }
PS:请记得在price
答案 1 :(得分:21)
在this related post的帮助下计算出来。
我将订单移出Home模型并进入可用性模型:
<强>状况强>
default_scope :order => "price ASC"
然后我急切地将可用性加载到Home模型中并按价格排序:
主强>
default_scope :include => :availabilities, :order => "availabilities.price ASC"
答案 2 :(得分:10)
@ecoologic answer:
scope :ordered, -> { includes(:availabilities).order('availabilities.price') }
很棒,但应该提到includes
可以,并且在某些情况下应该由joins
替换。 They both have their optimal use cases
从实际角度来看,有两个主要区别:
includes
加载相关记录;在这种情况下Availability
记录。 joins
请勿加载任何相关记录。因此,当您想要使用来自联接模型的数据时,您应该使用includes
,例如在某处显示price
。另一方面,如果您打算仅在查询中使用联接模型的数据,则应使用joins
。在ORDER BY
或WHERE
条款中。
includes
加载所有记录,而joins
仅加载那些具有关联联接模型的记录。因此,在OP的情况下,Home.includes(:availabilities)
会加载所有家庭,而Home.joins(:availabilities)
只会加载至少有一个可用性的家庭。
答案 3 :(得分:5)
在Rails 5.2+中,将字符串参数传递给order方法时可能会收到弃用警告:
DEPRECATION WARNING:使用非属性参数调用的危险查询方法(其参数用作原始SQL的方法):&#34; table.column&#34;。 Rails 6.0中不允许使用非属性参数。不应使用用户提供的值调用此方法,例如请求参数或模型属性。
要解决此问题,您可以使用Arel.sql()
:
scope :ordered, -> {
includes(:availabilities).order(Arel.sql('availabilities.price'))
}
答案 4 :(得分:3)
另一种实现方法:
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_table
模型上使用ActiveRecord
可以使您避免表名更改时发生的情况(但是这种情况很少发生)。
请注意,最好添加main_table#id
用于确定排序。
因此最终版本为:
scope :ordered, -> {
includes(:availabilities).
order(Availability.arel_table[:price].asc, order(Home.arel_table[:id].asc)
}
答案 5 :(得分:0)
您还可以像这样对链接表进行排序(例如):
class User
has_many :posts
end
class Post
belongs_to :user
scope :sorted_by_user_and_title, -> {
joins(:user).merge(
User.order(first_name: :asc, last_name: :asc)
)
.order(title: :desc)
# SELECT * FROM `posts`
# INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`
# ORDER BY
# `users`.`first_name` ASC, `users`.`last_name` ASC, `posts`.`title` DESC;
}
scope :sorted_by_title_and_user, -> {
order(title: :desc)
.joins(:user).merge(
User.order(first_name: :asc, last_name: :asc)
)
# SELECT * FROM `posts`
# INNER JOIN `users` ON `posts`.`user_id` = `users`.`id`
# ORDER BY
# `posts`.`title` DESC, `users`.`first_name` ASC, `users`.`last_name` ASC;
}
end
致谢