【问题标题】:Rails order by in associated modelRails 在关联模型中排序
【发布时间】:2009-07-14 18:38:27
【问题描述】:

我在 has_many 关系中有两个模型,例如 Log has_many Items。然后,Rails 很好地设置了以下内容:some_log.items,它将所有关联的项目返回到 some_log。如果我想根据 Items 模型中的不同字段对这些项目进行排序,有没有办法通过类似的构造来做到这一点,或者是否必须分解为以下内容:

Item.find_by_log_id(:all,some_log.id => "some_col DESC")

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    有多种方法可以做到这一点:

    如果您希望对该关联的所有调用都以这种方式排序,您可以在创建关联时指定排序,如下所示:

    class Log < ActiveRecord::Base
      has_many :items, :order => "some_col DESC"
    end
    

    您也可以使用 named_scope 执行此操作,这样可以在任何时候访问 Item 时轻松指定排序:

    class Item < ActiveRecord::Base
      named_scope :ordered, :order => "some_col DESC"
    end
    
    class Log < ActiveRecord::Base
      has_many :items
    end
    
    log.items # uses the default ordering
    log.items.ordered # uses the "some_col DESC" ordering
    

    如果您总是希望项目默认以相同的方式排序,您可以使用(Rails 2.3 中新增的)default_scope 方法,如下所示:

    class Item < ActiveRecord::Base
      default_scope :order => "some_col DESC"
    end
    

    【讨论】:

    • 从 Rails 3.x 开始,named_scope 语法略有不同。现在使用“范围”而不是“named_scope”来调用它,并使用函数来定义范围结构。例如:"scope :ordered, order("some_col DESC")"。
    • 在 Rails 4 中又有另一种方法。默认关联范围应指定为像 has_many :items, -&gt;{ order(:some_col).where(foo: 'bar') } 这样的 lambda,类似地,命名范围现在采用 lambda scope :name_of_scope, -&gt;{ where(foo: 'bar') }。默认范围采用块:default_scope: { where(foo: 'bar') }
    • 绝妙的答案。 +1
    【解决方案2】:

    rails 4.2.20 语法需要使用块调用:

    class Item < ActiveRecord::Base
      default_scope { order('some_col DESC') }
    end
    

    这也可以用另一种语法来写:

    default_scope { order(some_col: :desc) }
    

    【讨论】:

      【解决方案3】:

      这些都应该工作:

      Item.all(:conditions => {:log_id => some_log.id}, :order => "some_col DESC")
      some_log.items.all(:order => "some_col DESC")
      

      【讨论】:

        【解决方案4】:

        在你的模型类中设置default_scope

        class Item < ActiveRecord::Base
          default_scope :order => "some_col DESC"
        end
        

        这会起作用

        【讨论】:

        • @SsouLlesS 这在 2011 年没有 Rails 4 时得到了回答。
        【解决方案5】:

        按直接关系排序has_many :model

        Aaron回答here

        按关联关系排序has_many :modelable, through: :model

        class Tournament
          has_many :games # this is a join table
          has_many :teams, through: :games
        
          # order by :name, assuming team has this column
          def teams
            super.order(:name)
          end
        end
        
        Tournament.first.teams # are returned ordered by name
        

        【讨论】:

          【解决方案6】:

          对于使用较新版本的 Rails 遇到此问题的任何人,has_many 的第二个参数自 Rails 4.0.2 以来一直是可选范围。来自the docs 的示例(参见范围和选项示例)包括:

          has_many :comments, -> { where(author_id: 1) }
          has_many :employees, -> { joins(:address) }
          has_many :posts, ->(blog) { where("max_post_length > ?", blog.max_post_length) }
          has_many :comments, -> { order("posted_on") }
          has_many :comments, -> { includes(:author) }
          has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
          has_many :tracks, -> { order("position") }, dependent: :destroy
          

          如前所述,您也可以将块传递给has_many。 “这对于添加新的查找器、创建器和其他工厂类型的方法以用作关联的一部分很有用。” (same reference - 请参阅扩展)。

          这里给出的例子是:

          has_many :employees do
            def find_or_create_by_name(name)
              first_name, last_name = name.split(" ", 2)
              find_or_create_by(first_name: first_name, last_name: last_name)
            end
          end
          

          在更现代的 Rails 版本中,可以编写 OP 的示例:

          class Log < ApplicationRecord
            has_many :items, -> { order(some_col: :desc) }
          end
          

          请记住,这具有默认作用域的所有缺点,因此您可能更愿意将其添加为单独的方法:

          class Log < ApplicationRecord
            has_many :items
          
            def reverse_chronological_items
              self.items.order(date: :desc)
            end
          end
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多