Rails:在has_one关联上创建


100

嗨(这里是新的Rails新手),我有以下型号:

class Shop < ActiveRecord::Base
  belongs_to :user
  validates_uniqueness_of :title, :user_id, :message => "is already being used"
end

class User < ActiveRecord::Base
  has_one :shop, :dependent => :destroy
end

当我要创建新商店时,出现以下错误:

private method `create' called for nil:NilClass

这是我的控制器:

@user = current_user
@shop = @user.shop.create(params[:shop])

我通过在这里和那里阅读指南和教程尝试了不同的变体,但是我比以前更加困惑,无法正常工作。任何帮助将不胜感激。


编辑问题标题以反映问题。重复的在轨与HAS_ONE协会使用的构建
马克-安德烈·Lafortune

1
您也可以使用@user.build_shop(params)
ImranNaqvi

Answers:


123

首先,这是您想做的事情:

@user = current_user
@shop = Shop.create(params[:shop])
@user.shop = @shop

现在,这就是您的版本无法正常工作的原因:

您可能认为这可能有效,因为如果用户has_many与Shop 有关系,则@user.shops.create(params[:shop]) 可以正常工作。但是,两者之间有很大的不同has_many关系与has_one关系:

有了has_many关系shops返回一个ActiveRecord集合对象,该对象具有可用于向用户添加商店或从中删除商店的方法。这些方法之一是create,它将创建一个新商店并将其添加到用户。

有了has_one关系,您就不会取回这样的集合对象,而只能取回属于用户的Shop对象;如果用户还没有商店,则返回nil。由于Shop对象和nil都没有create方法,因此您不能createhas_one关系使用这种方式。


感谢您的回答,sepp2k。我现在知道为什么我的代码无法正常工作。
Neko 2010年

118
您也可以使用@user.create_shop(params[:shop])。请参见has_one添加的方法
2013年

选择的答案有效,但是@nates解决方案也有效。+1。
nfriend21

+1是答案,因为我也想知道,+ 1是解释原因的答案,+ 1是评论的最佳解决方案。
2013年

223

一种更简洁的方法是:

@user.create_shop(params[:shop])

请参阅Ruby on Rails指南中has_one添加的方法


6
这绝对是更好的方法
Magnum

7
请注意,如果您多次创建create_shop,它将删除以前的商店。例如,如果您运行@user.create_shop(params[:shop_one_info])它将创建shop_one,但是如果运行@user.create_shop(params[:shop_two_info])它将删除第一个商店并创建第二个商店。
ecoding5'6

上面有关删除以前的商店的注释是针对Rails 3.2.18的,不了解最新版本。5分钟后无法编辑评论-_-
ecoding5'5

找到一个解决方案,我没有在关联的模型上设置唯一性,因此请确保按照本示例的Shop模型中的设置方式进行操作。
ecoding5'6

您也可以使用@user.build_shop(params)
-ImranNaqvi

7

两个办法,如果你想要save,而不是create

shop = @user.build_shop
shop.save

shop = Show.new
shop.user = @user
shop.save

1

只需添加以上答案-

@user.create_shop(params[:shop])

上面的语法创建新记录,但随后删除相似的现有记录。

或者,如果您不想触发删除回调

Shop.create(user_id: user.id, title: 'Some unique title')

线程可能会有所帮助。点击这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.