สร้างเทียบกับใหม่ใน Rails 3


126

ใน Rails 3 เอกสารที่buildวิธีการสำหรับสมาคมอธิบายว่าเป็นเช่นเดียวกับnewวิธีการ แต่มีการกำหนดโดยอัตโนมัติของต่างประเทศที่สำคัญ ตรงจากเอกสาร:

Firm#clients.build (similar to Client.new("firm_id" => id))

ฉันเคยอ่านที่คล้ายกัน

อย่างไรก็ตามเมื่อฉันใช้new(เช่นsome_firm.clients.newไม่มีพารามิเตอร์ใด ๆ ) การfirm_idเชื่อมโยงของลูกค้าใหม่จะถูกสร้างขึ้นโดยอัตโนมัติ ฉันกำลังดูผลลัพธ์อยู่ในคอนโซลตอนนี้!

ฉันพลาดอะไรไปรึเปล่า? เอกสารล้าสมัยไปหน่อย (ไม่น่าเป็นไปได้) หรือเปล่า อะไรคือความแตกต่างระหว่างbuildและnew?


3
ผู้ที่กำลังมองหาคำตอบอย่างรวดเร็วโปรดตรวจสอบข้อที่ 2: "build" เป็นเพียงนามแฝงของ "new"
ivanreese

คำตอบ:


209

คุณกำลังอ่านเอกสารผิดเล็กน้อย some_firm.client.newคือการสร้างใหม่Clientวัตถุจากการเก็บลูกค้าและดังนั้นจึงสามารถตั้งค่าโดยอัตโนมัติfirm_idไปsome_firm.idในขณะที่เอกสารที่มีการเรียกร้องClient.newที่มีความรู้ของ id บริษัท ใด ๆ ที่ไม่ทั้งหมดดังนั้นจึงต้องการfirm_idผ่านไป

ข้อแตกต่างเพียงอย่างเดียวระหว่างsome_firm.clients.newและsome_firm.clients.buildดูเหมือนจะเป็นการbuildเพิ่มไคลเอ็นต์ที่สร้างขึ้นใหม่ในclientsคอลเล็กชัน:

henrym:~/testapp$ rails c
Loading development environment (Rails 3.0.4)
r:001 > (some_firm = Firm.new).save # Create and save a new Firm
#=> true 
r:002 > some_firm.clients           # No clients yet
#=> [] 
r:003 > some_firm.clients.new       # Create a new client
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:004 > some_firm.clients           # Still no clients
#=> [] 
r:005 > some_firm.clients.build     # Create a new client with build
#=> #<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil> 
r:006 > some_firm.clients           # New client is added to clients 
#=> [#<Client id: nil, firm_id: 1, created_at: nil, updated_at: nil>] 
r:007 > some_firm.save
#=> true 
r:008 > some_firm.clients           # Saving firm also saves the attached client
#=> [#<Client id: 1, firm_id: 1, created_at: "2011-02-11 00:18:47",
updated_at: "2011-02-11 00:18:47">] 

หากคุณกำลังสร้างออบเจ็กต์ผ่านการเชื่อมโยงbuildควรเลือกใช้มากกว่าnewเนื่องจากบิวด์เก็บอ็อบเจ็กต์ในหน่วยความจำของคุณsome_firm(ในกรณีนี้) ให้อยู่ในสถานะที่สอดคล้องกันก่อนที่อ็อบเจ็กต์จะถูกบันทึกลงในฐานข้อมูล


8
การใช้some_firm.client.newยังเพิ่มไคลเอ็นต์some_firm.clientsและการเรียกsaveใช้some_firmทำให้เกิดข้อผิดพลาดในการตรวจสอบที่ระบุว่าclientไม่ถูกต้อง ถ้าทั้งสองอย่างnewและbuildเพิ่มไคลเอนต์ใหม่ไปยังsome_firmคอลเลกชันไคลเอนต์สิ่งbuildที่newไม่ทำ? ฉันขอโทษที่มีคนหนาแน่นที่นี่!
ClosureCowboy

1
+1 ฉันได้รับผลลัพธ์ของคุณด้วย 3.0.4 ฉันจะรักถ้ามีคนที่มี 3.0.3 สามารถยืนยันได้ว่าฉันไม่ได้บ้า
ClosureCowboy

41
@henrym ดูเหมือนว่าใน 3.2.6 clients.new และ clients.build จะคล้ายกันทั้งคู่เพิ่มอ็อบเจกต์ใหม่ลงในคอลเลกชัน ฉันต้องการเพิ่มความคิดเห็นสำหรับทุกคนที่เจอสิ่งนี้ในขณะที่ Googling เหมือนฉัน
ฮับบาร์ด

11
ดูเหมือนว่าจะไม่มีความแตกต่างระหว่างพวกเขาใน Rails 3.2.3
Aditya Kapoor

4
คำตอบนี้ไม่ถูกต้องสำหรับ Rails> 3.2.13 โดยที่ 'build' เป็นเพียงนามแฝงของ 'new' ดูคำตอบของ @ HatemMahmoud ด้านล่าง
Andreas

92

buildเป็นเพียงนามแฝงสำหรับnew:

alias build new

ดูโค้ดทั้งหมดได้ที่https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74


13
alias build newณ ราง 3.2.13
fontno

7
นี่เป็นความจริงสำหรับบางสมาคม / ความสัมพันธ์เท่านั้น สมาคม Singular, ตัวอย่างเช่นมีความหมายที่แตกต่างกันอย่างสิ้นเชิงสำหรับและbuild build_#{association}ดูที่นี่และที่นี่
coreyward

1
ยังคงเป็นจริงสำหรับRails 4?
fatman13

1
นี่คือรายงานข้อผิดพลาด ... ซึ่งแสดงให้เห็นว่าคุณกำลังใช้งานใหม่เช่น restaurant.customers.new เพื่อหาลูกค้าใหม่ที่เกี่ยวข้องกับร้านอาหารโดยไม่ต้องต่อท้ายกับร้านอาหารลูกค้าเพื่อใช้ขอบเขต ... เช่นร้านอาหาร .customers.scoped.new
user3334690

11

คุณถูกต้องการสร้างและฟังก์ชันใหม่มีผลเหมือนกันในการตั้งค่าคีย์ภายนอกเมื่อถูกเรียกผ่านการเชื่อมโยง ฉันเชื่อว่าเหตุผลที่เอกสารถูกเขียนเช่นนี้เพื่อชี้แจงว่าอ็อบเจ็กต์ไคลเอ็นต์ใหม่กำลังถูกสร้างอินสแตนซ์ซึ่งตรงข้ามกับความสัมพันธ์ของเรกคอร์ดใหม่ที่ใช้งานอยู่ นี่เป็นผลเช่นเดียวกับการเรียก. new ในคลาสที่จะมีใน Ruby กล่าวคือเอกสารชี้แจงว่าการเรียก build บนการเชื่อมโยงนั้นเหมือนกันคือการสร้างอ็อบเจ็กต์ใหม่ (เรียก. new) และส่งคีย์ต่างประเทศไปยังอ็อบเจ็กต์นั้น คำสั่งเหล่านี้เทียบเท่ากันทั้งหมด:

Firm.first.clients.build
Firm.first.clients.new
Client.new(:firm_id => Firm.first.id)

ฉันเชื่อว่าเหตุผลที่. build มีอยู่คือ Firm.first.clients.new อาจถูกตีความหมายว่าคุณกำลังสร้างออบเจ็กต์ความสัมพันธ์ has_many ใหม่แทนที่จะเป็นไคลเอนต์จริงดังนั้นการเรียก. build จึงเป็นวิธีการชี้แจงสิ่งนี้


ดังนั้นพวกเขาจึงมีความเทียบเท่า นั่นคือสิ่งที่ดูเหมือน ขอบคุณ!
ClosureCowboy

5
สิ่งนี้ไม่ถูกต้อง สองตัวแรกเทียบเท่ากันใน Rails รุ่นใหม่กว่า (ดูเหมือนว่าตอนที่โพสต์จะไม่ใช่) แต่สุดท้ายมีความแตกต่างอย่างมีนัยสำคัญใน Firm.first.clients จะไม่มีไคลเอนต์ใหม่
tybro0103

4

buildเทียบกับnew:

ส่วนใหญ่ใหม่และสร้างเหมือนกัน แต่การสร้างร้านค้าวัตถุในหน่วยความจำ ,

เช่น:

สำหรับใหม่:

Client.new(:firm_id=>Firm.first.id)

สำหรับการสร้าง:

Firm.first.clients.build

ที่นี่ลูกค้าจะถูกเก็บไว้ในหน่วยความจำเมื่อบันทึก บริษัท บันทึกที่เกี่ยวข้องจะถูกบันทึกด้วย


2

Model.new

Tag.new post_id: 1จะเริ่มต้นแท็กด้วยpost_idชุด

@ model.models.new

@post.tags.buildทำเช่นเดียวกันและแท็กอินสแตนซ์จะอยู่ใน@post.tagsก่อนที่จะบันทึก

ซึ่งหมายความว่า@post.saveจะบันทึกทั้ง @post และแท็กที่สร้างขึ้นใหม่ (สมมติว่าตั้งค่า: inverse_of) สิ่งนี้ดีมากเพราะ Rails จะตรวจสอบความถูกต้องของวัตถุทั้งสองก่อนที่จะบันทึกและจะไม่มีการบันทึกหากหนึ่งในนั้นไม่ผ่านการตรวจสอบความถูกต้อง

Models.new เทียบกับ models.build

@post.tags.buildและ@post.tags.newเทียบเท่า (อย่างน้อยตั้งแต่ Rails 3.2)


แล้วเป็นอย่างไรThe only difference between some_firm.clients.new and some_firm.clients.build seems to be that build also adds the newly-created client to the clients collection:บ้าง?
アレックス
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.