2014-03-12 49 views
1

所以我新的領域,並沒有真正理解他們well.Let說,我有2種型號,ProjectTicket簡單的範圍和關聯

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

一nd現在當我使用Project.default我找回ActiveRecord::Relation,並沒有線索如何訪問相關tickets

+0

@DaveNewton你會用什麼? lambdas是默認的方式繼續Rails 4我認爲 – apneadiving

+0

@apneadiving我想我仍然喜歡類方法;它在Rails文檔中被列爲首選項,並且在有參數時首選 - 我喜歡讓它們保持一致,YMMV。 –

+0

@DaveNewton我瞭解你的觀點,我通常使用lambda表達式,因爲我喜歡'scope'方法,它使事情變得非常清晰(對我來說) – apneadiving

回答

2

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 

一定要處理情況:

  • 當有不止一個匹配
  • 當沒有比賽
+0

我的默認範圍預計只返回一個項目,所以我希望避免編寫project = project.first而直接返回該記錄,但我認爲這不適用於範圍? – Zed

+0

不,範圍應該過濾集合。編寫一個類的方法,如果你想,讓我編輯我的答案 – apneadiving

0

一個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 

錯誤

你得到一個關係的原因是beca當你使用where時,你基本上會獲得一個「數組」數據(而不是單個記錄)。如果您.each通過數據或只返回.first,你會得到一個實際的對象,你可以輸出:

@defaults = Project.defaults 
@defaults.each do |project| 
    project.tickets #-> associated tickets 
end 
0

使用allfirst完成查詢。

#get all default projects 
Project.default.all 

#get the first default project 
Project.default.first