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])

ฉันได้ลองใช้รูปแบบต่างๆโดยอ่านคู่มือและแบบฝึกหัดที่นี่และที่นั่น แต่ฉันสับสนมากกว่าเดิมและไม่สามารถใช้งานได้ ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก.


แก้ไขชื่อคำถามเพื่อสะท้อนคำถาม ซ้ำกันของการใช้งาน build ที่มีการเชื่อมโยง 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ความสัมพันธ์:

ด้วยhas_manyความสัมพันธ์shopsจะส่งคืนอ็อบเจ็กต์คอลเลกชัน ActiveRecord ซึ่งมีวิธีการที่คุณสามารถใช้เพื่อเพิ่มและลบร้านค้าไปยัง / จากผู้ใช้ วิธีหนึ่งคือcreateสร้างร้านค้าใหม่และเพิ่มให้กับผู้ใช้

ด้วยhas_oneความสัมพันธ์คุณจะไม่ได้รับคืนวัตถุคอลเลกชันดังกล่าว แต่เป็นเพียงวัตถุร้านค้าที่เป็นของผู้ใช้หรือไม่มีถ้าผู้ใช้ยังไม่มีร้านค้า เนื่องจากไม่มีวัตถุ Shop หรือศูนย์ไม่มีcreateวิธีคุณจึงไม่สามารถใช้createวิธีนี้กับhas_oneความสัมพันธ์ได้


ขอบคุณสำหรับคำตอบ sepp2k ฉันเข้าใจแล้วว่าทำไมรหัสของฉันถึงใช้งานไม่ได้
Neko

119
@user.create_shop(params[:shop])นอกจากนี้คุณยังสามารถใช้ ดูวิธีการเพิ่มโดย has_one
Nates

คำตอบที่เลือกใช้งานได้ แต่โซลูชัน @nates ก็ใช้ได้เช่นกัน +1 ให้คุณทั้งคู่
nfriend21

+1 สำหรับคำตอบเพราะฉันสงสัยเหมือนกัน +1 คำตอบเพื่ออธิบายว่าเหตุใดจึงเป็นเช่นนั้นและ +1 ให้กับความคิดเห็นเพื่อให้คำตอบที่ดีที่สุด
deivid

224

วิธีที่กระชับกว่านี้คือ:

@user.create_shop(params[:shop])

ดูวิธีที่เพิ่มโดย has_oneในคำแนะนำ Ruby on Rails


6
นี่เป็นแนวทางที่ดีกว่าแน่นอน
Magnum

7
ระวังว่าหากคุณสร้างร้านค้ามากกว่าหนึ่งครั้งจะเป็นการลบร้านค้าก่อนหน้านี้ ตัวอย่างเช่นหากคุณเรียกใช้@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

คุณสามารถใช้งานได้@user.build_shop(params)
ImranNaqvi


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.