Rails – 按连接表数据排序
我在工作中有一个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
(第一个=最低)自动订购Homes? 也许是default_scope :order
东西default_scope :order
?
我建议避免使用default_scope
,尤其是在另一个表上的价格之类的东西上。 每次使用该表时,都会进行连接和排序,可能会在复杂查询中产生奇怪的结果,并且无论如何都会使查询变慢。
它的范围没有任何问题,它更简单,更清晰,你可以简单地说:
scope :ordered, -> { includes(:availabilities).order('availabilities.price') }
PS:记得在price
上添加一个索引
在这篇相关文章的帮助下想出来了。
我将订单从Home模型移到了Availability模型中:
可用性
default_scope :order => "price ASC"
然后我急切地将可用性加载到Home模型中并按价格排序:
家
default_scope :include => :availabilities, :order => "availabilities.price ASC"
@ecoologic 答案 :
scope :ordered, -> { includes(:availabilities).order('availabilities.price') }
是伟大的,但应该提到includes
可能,在某些情况下应该被joins
取代。 他们都有自己的最佳用例 。
从实际角度来看,有两个主要区别:
-
includes
相关记录的负载; 在这种情况下Availability
记录。joins
不加载任何关联的记录。 因此,当您想要使用来自连接模型的数据时,您应该使用includes
,例如在某处显示price
。 另一方面,如果您打算仅在查询中使用连接模型的数据,例如在ORDER BY
或WHERE
子句中,则应使用连接。 -
includes
加载所有记录,而joins
只加载那些具有关联连接模型的记录。 因此,在OP的情况下,Home.includes(:availabilities)
将加载所有家庭,而Home.joins(:availabilities)
将仅加载至少具有一个可用性的家庭。
另见这个问题 。
在Rails 5.2+中,在将字符串参数传递给order方法时,您可能会收到弃用警告:
DEPRECATION WARNING:使用非属性参数调用的危险查询方法(其参数用作原始SQL的方法):“table.column”。 Rails 6.0中不允许使用非属性参数。 不应使用用户提供的值调用此方法,例如请求参数或模型属性。
要解决此问题,您可以使用Arel.sql()
:
scope :ordered, -> { includes(:availabilities).order(Arel.sql('availabilities.price')) }
另一种实现此目的的方法:
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) }
在ActiveRecord
模型上使用arel_table
可以在表名更改时保存方案(但很少发生)。
请注意,为确定性排序添加main_table#id
是很好的。
所以最终版本将是:
scope :ordered, -> { includes(:availabilities). order(Availability.arel_table[:price].asc, order(Home.arel_table[:id].asc) }
- Rails ActiveRecord:Three Table has_many through:associations
- ActiveRecord has_many:通过在批量分配上复制计数器缓存
- 如何查找记录,其has_many通过对象包括某些列表的所有对象?
- 获取has_many:x,:through =>:y的问题在控制台中工作
- Activeadmin formtastic动态选择
- HMT collection_singular_ids =删除连接模型是直接的,不会触发销毁回调
- NameError:has_many通过关系的未初始化常量
- Ruby on Rails在保存之前通过关联对象具有很多function
- 动态创建has_many或habtm的after_add和after_remove回调?