2012-11-05 58 views
5

我對Rails還是比較新的,所以希望這不是一個愚蠢的問題。訪問has_one關聯的屬性

我有兩種模式:用戶和家務。用戶HAS_ONE苦差事,並家務屬於用戶

class User < ActiveRecord::Base 
    attr_accessible :chore_done, :email, :name, :phone 
    has_one :chore 

class Chore < ActiveRecord::Base 
    attr_accessible :name, :user_id 
    belongs_to :user 

在我的用戶指標,我想展示的所有用戶,並顯示與他或她相關的苦差事。我通過傳遞User.all到視圖和使用。每次通過每個用戶重複這樣做:

<% @users.each do |user| %> 
    <tr> 
    <td><%= user.name %></td> 
    <td><%= user.chore.name %></td> 
    <td><%= user.chore_done? %></td> 
    <td><%= link_to 'Edit', edit_user_path(user) %></td> 
    <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td> 
    </tr> 
<% end %> 

不幸的是,我無法訪問家務的name屬性。我得到這個錯誤:

undefined method `name' for nil:NilClass

如果我刪除了.name屬性,它只是返回一個指向Chore對象的指針。

我有一種感覺,這與將User.all對象傳遞給視圖然後迭代該視圖有關。只需在控制檯中訪問特定的User對象(例如User.find(1)),然後訪問user.chore.name就可以正常工作。

1.9.3-p194 :045 > user = User.find(4) 
    User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 4]] 
=> #<User id: 4, name: "Example User", email: "[email protected]", phone: 8675309, chore_done: false, created_at: "2012-11-05 01:53:33", updated_at: "2012-11-05 01:53:33"> 
1.9.3-p194 :046 > user.chore.name 
    Chore Load (0.3ms) SELECT "chores".* FROM "chores" WHERE "chores"."user_id" = 4 LIMIT 1 
=> "Living room" 

我在APIDock上讀了一些關於AssociationProxy的內容,但我不認爲我完全理解它,也不知道如何使用它。從我收集的信息中,訪問模型中的所有對象都會返回一個對象數組,但不會爲其依賴關係返回一組完整的屬性?因此,在這種情況下,我得到一個指向Chore對象的指針,但沒有訪問它的任何屬性。

我當然可以在我的用戶表中添加Chore作爲另一列,但我可能在將來添加到該模型+我只是想弄清楚has_one關聯是如何工作的。

任何幫助表示讚賞!

回答

3

undefined method `name' for nil:NilClass

這是說你試圖調用一些方法name()上的Nil的一個實例。在你的代碼的背景下,說chore在這條線是nil

<td><%= user.chore.name %></td> 

簡單地說,在@userUser一個實例沒有關聯Chore。在您的視圖中容納這一點的一個簡單方法是檢查user.chore是否存在。

<td><%= user.chore.nil? ? "some default name" : user.chore.name %></td> 
+0

啊!這很有道理。我做得比現在複雜得多。只是分解你寫的東西......我之前在rails中沒有看到過這種語法(第二個問號),但它看起來與SQL查詢非常相似。涼! – jasdeepg

+0

它被稱爲**三元操作符**。 (條件)? 「true case」:「false case」' – deefour

+3

時髦的方式來避免使用rails的三元組:'user.chore.try(:name)'http://apidock.com/rails/Object/try –

5

這是因爲並不是每個用戶都有與之相關的雜事。

有幾種方法可以解決這個問題;我偏向於使用Array()強制收集的迭代模式。你可以在你看來這樣做:如果chore是零

<% Array(user.chore).each do |chore| %> 
    <td><%= chore.name %></td> 
    <td><%= chore.done? %></td> 
<% end %> 

Array()將實例化一個空數組,沒什麼意思,當您嘗試遍歷它發生。如果存在雜項,它將迭代[chore]

這種模式的好處是它不違反Tell don't ask。詢問一個對象是否是nil?也是可能的,但它更多的是一種程序技術,它不利用Ruby強大的面向對象功能。

編輯

由於Deefour指出,這將導致不匹配的列的表。你應該使用他的解決方案來處理這種情況。

+0

這將導致一個漂亮的表格 – deefour

+0

你能詳細點嗎? –

+0

啊,你說得對。對不起,我不會注意桌子的其餘部分。 –

4

下面是一個使用Rails的代表模塊的另一種選擇:

class User < ActiveRecord::Base 
    has_one :chore 
    delegate :name, to: :chore, prefix: true, allow_nil: true 
end 

這將允許你打電話<%= user.chore_name %>,這將在name呼叫傳遞到苦差事,返回nil如果是沒有的。

+0

':allow_nil - 如果設置爲true,則阻止引發NoMethodError –

0

另一種選擇:

<td><%= user.chore.try(:name) %></td> 

這將返回nil如果沒有user.chore