代码之家  ›  专栏  ›  技术社区  ›  Zed

简单范围和关联

  •  1
  • Zed  · 技术社区  · 12 年前

    所以我对示波器很陌生,并不是很了解。假设我有两个模型, Project Ticket :

    class Project < ActiveRecord::Base
     has_many :tickets
    end
    
    class Ticket < ActiveRecord::Base
     belongs_to :project
    end
    

    我习惯于用这样的代码从票据中访问相关数据:

    Project.find(1).tickets.each do |ticket|
     puts ticket.name
    end
    

    我创建了新范围:

    scope :default, -> { where(default: true) }
    

    现在当我使用 Project.default 我回来了 ActiveRecord::Relation 并且不知道如何访问关联的 tickets ?

    3 回复  |  直到 12 年前
        1
  •  2
  •   apneadiving    12 年前

    Project.default确实会返回 ActiveRecord::Relation ,这是一个“待触发”查询。一旦您开始循环等,查询就会被触发,这对您来说有点透明。

    如果您想从项目中获得门票,首先我建议您将其包含在查询中,以避免N+1。这样做:

    projects = Project.default.includes(:tickets)
    

    然后访问特定项目的门票:

    project = projects.first
    project.tickets 
    

    如果希望方法始终返回单个对象:

    class Project < ActiveRecord::Base
      has_many :tickets
    
      def self.get_default_with_tickets
        Project.where(default: true).includes(:tickets).first
      end
    end
    

    那么:

    Project.get_default_with_tickets #=> your_project
    

    务必处理以下情况:

    • 当有多个匹配时
    • 当没有匹配项时
        2
  •  0
  •   Richard Peck    12 年前

    A. scope 基本上只是一个 class method (在未初始化模型上激发的):

    class Project < ActiveRecord::Base
     has_many :tickets
     scope :defaults, -> { where(default: true) }
    end
    

    这意味着如果您这样做:

    @defaults = Project.defaults
    

    …你得到了所有的 project 具有属性的对象 default 如真

    这与以下内容相同:

    class Project < ActiveRecord::Base
     has_many :tickets
     def self.defaults
          where(default: true)
     end
    end
    

    错误

    你建立关系的原因是因为当你使用 where ,你基本上得到了一个“数组”的数据(而不仅仅是一个记录)。如果你 .each 通过数据或只是返回 .first ,您将获得一个可以输出的实际对象:

    @defaults = Project.defaults
    @defaults.each do |project|
        project.tickets #-> associated tickets
    end
    
        3
  •  0
  •   Max Williams    12 年前

    使用 all first 以完成查询。

    #get all default projects
    Project.default.all 
    
    #get the first default project
    Project.default.first