【问题标题】:Rails - Sort by join table dataRails - 按连接表数据排序
【发布时间】:2012-03-01 03:26:58
【问题描述】:

我有一个 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

【问题讨论】:

    标签: ruby-on-rails ruby join has-many-through


    【解决方案1】:

    this related post 的帮助下解决了这个问题。

    我将排序从 Home 模型移到了 Availability 模型中:

    可用性

    default_scope :order => "price ASC"
    

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

    首页

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

    【讨论】:

      【解决方案2】:

      我建议避免使用default_scope,尤其是在另一张桌子上的价格之类的东西上。每次您使用该表时,都会进行连接和排序,这可能会在复杂查询中产生奇怪的结果,并且无论如何都会使您的查询变慢。

      它自己的范围没有什么问题,它更简单,更清晰,你可以让它变得简单:

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

      PS:记得在price上添加索引;另请参阅此处的其他出色答案,以在 join/include 之间做出决定。

      【讨论】:

      • 你需要使用includes而不是joins吗?
      • 视情况而定,@TeWu 在解释他的答案的差异方面做得很好。尤其是 Tom Dallimore 博客的链接非常棒。
      【解决方案3】:

      @ecoologicanswer:

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

      很好,但应该提到includes 可以,并且在某些情况下应该由joins 代替。它们都有自己的最佳用例(请参阅:#1#2)。

      从实际的角度来看,有两个主要区别:

      1. includes 加载相关记录;在这种情况下 Availability 记录。 joins 不加载任何关联的记录。因此,当您想使用连接模型中的数据时,您应该使用includes,例如在某处显示price。另一方面,如果您打算仅在查询中使用连接模型的数据,则应使用joins,例如在ORDER BYWHERE 子句中。

      2. includes 加载所有记录,而joins 仅加载具有关联连接模型的那些记录。因此,在 OP 的情况下,Home.includes(:availabilities) 将加载所有房屋,而Home.joins(:availabilities) 将仅加载与至少一个可用性相关联的房屋。

      另见this question

      【讨论】:

      • 最佳用例链接现已断开
      • 感谢您的信息。链接已断开,因为链接的博客已死……真可惜。我已经链接到这篇博文的存档版本,还添加了一个链接到一些关于这个主题的非史前博文;)
      【解决方案4】:

      在 Rails 5.2+ 中,将字符串参数传递给 order 方法时,您可能会收到弃用警告:

      弃用警告:使用非属性参数调用的危险查询方法(其参数用作原始 SQL 的方法):“table.column”。 Rails 6.0 将不允许使用非属性参数。不应使用用户提供的值(例如请求参数或模型属性)调用此方法。

      要解决这个问题,你可以使用Arel.sql()

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

      【讨论】:

        【解决方案5】:

        实现此目的的另一种方法:

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

        【讨论】:

          【解决方案6】:

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

          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
          

          问候

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多