我还是Rails的新手,所以希望这不是一个愚蠢的问题。
我有两个模型:用户和家务。用户has_one杂事,Chore属于User
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传递给视图并使用.each来遍历每个用户:
<% @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 %>
不幸的是,我无法访问Chore的name属性。我收到这个错误:
nil的未定义方法`name':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: "example@dot.com", 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的内容,但我认为我并不完全理解它,也不知道如何使用它。根据我收集的内容,访问模型中的所有对象会返回一个对象Array,但是不会为其依赖项返回一组完整的属性?因此,在这种情况下,我得到一个指向Chore对象的指针,但是不能访问它的任何属性。
我当然可以在我的用户表中添加Chore作为另一个列,但我可能会在将来添加到该模型+我只是想弄清楚has_one关联如何工作。
感谢任何帮助!
答案 0 :(得分:5)
这是因为不是每个用户都有与之相关的杂务。
有几种方法可以解决这个问题;我偏爱使用Array()
来强制收集的迭代模式。您可以在视图中执行此操作:
<% Array(user.chore).each do |chore| %>
<td><%= chore.name %></td>
<td><%= chore.done? %></td>
<% end %>
如果Array()
为nil, chore
将实例化一个空数组,这意味着当您尝试迭代它时没有任何反应。如果存在杂项,它将迭代[chore]
。
这种模式的好处是它不违反Tell don't ask。询问对象是否为nil?
也是可能的,但它更多的是一种不利用Ruby强大的面向对象特性的过程技术。
修改强>
正如Deefour指出的那样,这会导致列中列不匹配。你应该在这种情况下使用他的解决方案。
答案 1 :(得分:5)
这是使用Rails'委托模块的另一个选项:
class User < ActiveRecord::Base
has_one :chore
delegate :name, to: :chore, prefix: true, allow_nil: true
end
这样您就可以拨打<%= user.chore_name %>
,将name
来电转移到杂项上,如果没有,则返回nil
。
答案 2 :(得分:3)
nil的未定义方法`name':NilClass
这表示您尝试在name()
的实例上调用某个方法Nil
。在代码的上下文中,该行表示chore
nil
<td><%= user.chore.name %></td>
简单地说,User
中的@user
个实例之一没有关联的Chore
。在视图中容纳此内容的一种简单方法是检查user.chore
是否存在。
<td><%= user.chore.nil? ? "some default name" : user.chore.name %></td>
答案 3 :(得分:0)
另一种选择:
<td><%= user.chore.try(:name) %></td>
如果没有nil
,则会返回user.chore
。