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 연관이있는 빌드 사용
Marc-André Lafortune

1
당신은 또한 사용할 수 있습니다@user.build_shop(params)
ImranNaqvi

답변:


123

우선, 원하는 작업을 수행하는 방법은 다음과 같습니다.

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

이제 버전이 작동하지 않는 이유는 다음과 같습니다.

당신은 아마 사용자가 있었다면이 힘의 일이 있기 때문에 생각 has_many숍의 관계를 @user.shops.create(params[:shop]) 것입니다 작동합니다. 그러나 has_many관계와 has_one관계 에는 큰 차이가 있습니다 .

A의 has_many관계, shops당신은 사용자로부터 /에 상점을 추가하고 제거하는 데 사용할 수있는 방법이있는 액티브 컬렉션 객체를 반환합니다. 이러한 방법 중 하나는 create새 상점을 만들고 사용자에게 추가하는입니다.

has_one관계를 사용하면 이러한 컬렉션 개체가 아니라 단순히 사용자에게 속한 Shop 개체를 반환하거나 사용자에게 아직 상점이없는 경우 nil을 반환합니다. Shop 객체도 nil도 create메소드 가 없기 때문에 관계에 create이런 방식으로 사용할 수 없습니다 has_one.


답변 해 주셔서 감사합니다, sepp2k. 이제 내 코드가 작동하지 않는 이유를 알 수 있습니다.
Neko

118
당신은 또한 사용할 수 있습니다 @user.create_shop(params[:shop]). has_one에 의해 추가 된 메소드를 참조하십시오 .
궁둥이

선택한 답변이 작동하지만 @nates 솔루션도 작동합니다. 둘 다 +1합니다.
nfriend21

내가 똑같이 궁금해서 답변에 +1, 이유를 설명하는 답변에 +1, 최상의 솔루션을 제공하는 댓글에 +1.
deivid

224

이를 수행하는 더 간결한 방법은 다음과 같습니다.

@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

이전 상점 삭제에 대한 위의 의견은 Rails 3.2.18에 대한 것이며 최신 버전에 대해서는 모릅니다. 수 없습니다 편집 주석 -_- 5 분 후
ecoding5

솔루션을 찾았지만 관련 모델에 고유성을 설정하지 않았으므로이 예제의 Shop 모델에서 설정 한대로 수행해야합니다.
ecoding5

당신은 사용합니다 alse 수@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')

스레드 가 도움 이 될 수 있습니다. 여기를 클릭하세요

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.