ruby Rails -按连接表数据排序

cu6pst1q  于 2023-10-18  发布在  Ruby
关注(0)|答案(6)|浏览(94)

我有一个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
  • 数据库中的“availabilities”表有额外的数据列“price”*

所以现在我可以打电话

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

并按我的要求返回按价格排序的可用性数据。我的问题是:
有没有一种方法可以自动排序房屋avaliabilities.first.price(第一=最低)?比如default_scope :order

vxf3dgd4

vxf3dgd41#

我建议避免使用default_scope,特别是在另一张table上的价格之类的东西上。每次使用该表时,都会发生连接和排序,这可能会在复杂查询中产生奇怪的结果,并且无论如何都会使查询变慢。
有一个自己的作用域没有什么错,它更简单,更清晰,你可以让它简单到:

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

我称之为price_ordered
PS:记得在price上添加索引;也可以在这里看到其他很好的答案,以决定加入/包含**。

0s0u357o

0s0u357o2#

this related post的帮助下完成。
我将订购从Home模型转移到了Availability模型:

可用性

default_scope :order => "price ASC"

然后,我急切地将可用性加载到Home模型中,并按价格排序:

返回首页

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

wyyhbhjk3#

@ecoologic answer

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

includes是很好的,但应该提到的是,includes可以,在某些情况下应该被joins取代。它们都有各自的最佳用例(请参阅:#1#2)。
从实践的Angular 来看,有两个主要的区别:

  1. includes加载关联记录;在本例中为Availability记录。joins不加载任何关联记录。因此,当你想使用来自连接模型的数据时,你应该使用includes。在某处显示price。另一方面,如果你只打算在查询中使用连接模型的数据,那么应该使用joins。在ORDER BYWHERE子句中。
  2. includes加载所有记录,而joins仅加载那些具有关联联接模型的记录。因此,在OP的情况下,Home.includes(:availabilities)将加载所有家庭,而Home.joins(:availabilities)将只加载那些至少关联了一个可用性的家庭。
    参见this question
jq6vz3qz

jq6vz3qz4#

另一种方法来实现这一点:

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)
}
apeeds0o

apeeds0o5#

在Rails 5.2+中,当向order方法传递字符串参数时,您可能会收到一个弃用警告:
降级警告:使用非属性参数调用的危险查询方法(其参数用作原始SQL的方法):“table.column”。Rails 6.0中不允许使用非属性参数。不应使用用户提供的值(如请求参数或模型属性)调用此方法。
要解决这个问题,可以使用Arel.sql()

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

kb5ga3dv6#

你也可以像这样对链接表进行排序(例如):

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

问候

相关问题