Rails has_many 和 has_one 在 build 方法上的区别

alex · 2012年06月15日 · 最后由 everpointer 回复于 2014年11月01日 · 7304 次阅读

不知道有多少人跟我一样在这里载坑了

本来是想用 accepts_nested_attributes_for 写一个 nested form

class User < ActiveRecord::Base
  attr_accessible :email, :account_attributes
  has_one :account
  accepts_nested_attributes_for :account
end


class Account < ActiveRecord::Base
  attr_accessible :password, :password_confirmation
  has_secure_password
  belongs_to :user 
end


class UsersController < ApplicationController
  def new
    @user = User.new
  end
end

view 里

<%= form_for @user do |f| %>
  email: <%= f.text_field :name %>
  <%= f.fields_for :account do |account_form| %>
    password: <%= account_form.password_field :password %>
    password_confirmation: <%= account_form.password_field :password_confirmation %>
  <% end %>
<% end %>

一开始无法显示 account 里的内容,后来发现没有在 controller 里 build account, 于是

class UsersController < ApplicationController
  def new
    @user = User.new
    @user.account.build
  end
end

报错 undefined method `build' for nil:NilClass

刚开始怎么也想不通,隔了一天去翻http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html 才发现原来 has_one 的 build 方法是 build_association 而不是 collection.build。因为不常用 has_one,rails 里“约定”又比较多,才会当 has_many 的方法来写。

把 controller 里改成

class UsersController < ApplicationController
  def new
    @user = User.new
    @user.build_account
  end
end

程序才正常跑起来

一言蔽之 在 has_many 中:User#accounts.build 在 has_one 中:User#build_account

匿名 #1 2012年06月15日

赞最后一句话,言简意赅。学习了。

学习了。

原来是这样子,好像从来没用使用过 has_one

没有用过,学习了。 提一点自己的想法:对于我们 rubyist,学代码时有时候需要一个功能时,经常会在脑海中产生一个方法,这个方法可能我们并没有用过,有可能是根据其他类类比出来的,也可能是自己 yy 出来的; 而 ruby 也一直在纵容我们这个'坏习惯'。所以对于上面的这种情况,是有违这种习惯的,是不是可以将他们一致化,这样就不需要记忆这种区别了。

收藏了,谢谢!

这两天被这个坑也纠缠了很久。 更干净的写法我觉得是是:

class User attr_accessible :account, :account_attributes

has_one :account

accepts_nested_attributes_for :account

after_initialize do self.account ||= self.build_account() end end

这样就不需要在 controller 里面惦记 build 了。

原来是这样 , 谢谢啊 , 搞了半天~

1 年前的帖子啊,我也被坑了,3Q

需要 登录 后方可回复, 如果你还没有账号请 注册新账号