Xây dựng so với mới trong Rails 3


125

Trong tài liệu Rails 3 , buildphương thức cho các hiệp hội được mô tả giống như newphương thức, nhưng với sự gán tự động của khóa ngoại. Trực tiếp từ các tài liệu:

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

Tôi đã đọc tương tự ở nơi khác.

Tuy nhiên, khi tôi sử dụng new(ví dụ some_firm.clients.newkhông có bất kỳ tham số nào), firm_idliên kết của máy khách mới sẽ tự động được tạo. Tôi đang nhìn vào kết quả ngay bây giờ trong bảng điều khiển!

Tui bỏ lỡ điều gì vậy? Các tài liệu có một chút lỗi thời (không có khả năng)? Sự khác biệt giữa buildvà là newgì?


3
Mọi người đang tìm kiếm một câu trả lời nhanh chóng, kiểm tra câu thứ 2 trở xuống: "bản dựng" chỉ là bí danh cho "mới"
ivanreese

Câu trả lời:


208

Bạn đang đọc sai các tài liệu một chút. some_firm.client.newđang tạo ra một mới Clientđối tượng từ bộ sưu tập của khách hàng, và vì vậy nó có thể tự động thiết lập firm_idđể some_firm.id, trong khi các tài liệu được gọi Client.newmà không có kiến thức về id của bất kỳ Công ty nào cả, vì vậy nó cần firm_idđược truyền cho nó.

Sự khác biệt duy nhất giữa some_firm.clients.newsome_firm.clients.builddường như buildcũng là thêm ứng dụng khách mới được tạo vào clientsbộ sưu tập:

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

Nếu bạn đang tạo một đối tượng thông qua một liên kết, buildnên được ưu tiên hơn newvì bản dựng giữ cho đối tượng trong bộ nhớ của bạn, some_firm(trong trường hợp này) ở trạng thái nhất quán ngay cả trước khi bất kỳ đối tượng nào được lưu vào cơ sở dữ liệu.


8
Sử dụng some_firm.client.newcũng cho biết thêm khách hàng để some_firm.clients, và kêu gọi savetrên some_firmdẫn đến một lỗi xác nhận chỉ ra rằng clientkhông hợp lệ. Nếu cả hai newbuildthêm ứng dụng khách mới vào some_firmbộ sưu tập máy khách của mình, thì buildđiều đó newkhông làm gì? Tôi xin lỗi vì đã dày đặc, ở đây!
ClosCowboy

1
+1 Tôi đã nhận được kết quả của bạn với 3.0.4. Tôi thích nếu ai đó có 3.0.3 có thể xác nhận tôi không điên.
ClosCowboy

41
@henrym Có vẻ như trong 3.2.6 client.new và client.build giống nhau ở cả hai đều thêm đối tượng mới vào bộ sưu tập. Tôi muốn thêm một nhận xét cho bất kỳ ai gặp phải điều này trong khi Googling như tôi đã làm
hubbard

11
Có vẻ như không có sự khác biệt giữa chúng trong Rails 3.2.3
Aditya Kapoor

4
Câu trả lời này không chính xác cho Rails> 3.2.13, trong đó 'build' chỉ là bí danh cho 'new'. Xem câu trả lời của @ HHRMahmoud dưới đây.
Andreas

91

buildchỉ là một bí danh cho new:

alias build new

Mã đầy đủ có thể được tìm thấy: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb#L74


13
alias build newkể từ đường ray 3.2.13
fontno

7
Điều này chỉ đúng với một số hiệp hội / quan hệ. Các hiệp hội số ít, ví dụ, có định nghĩa hoàn toàn khác nhau cho buildbuild_#{association}. Xem ở đâyở đây .
coreyward

1
Điều này vẫn đúng cho Rails 4?
fatman13

1
đây là báo cáo lỗi ... gợi ý nếu bạn đang sử dụng mới như nhà hàng.customers.new, như một cách để có một khách hàng mới liên kết với nhà hàng mà không thêm nó vào nhà hàng. Khách hàng, sử dụng phạm vi ... như nhà hàng .customers.scoped.new
user3334690

11

Bạn đã đúng, các hàm xây dựng và các hàm mới có cùng tác dụng là đặt khóa ngoại, khi chúng được gọi thông qua một liên kết. Tôi tin rằng lý do tài liệu được viết như thế này là để làm rõ rằng một đối tượng Khách hàng mới đang được khởi tạo, trái ngược với mối quan hệ hồ sơ hoạt động mới. Đây là hiệu ứng tương tự như việc gọi .new trên một lớp sẽ có trong Ruby. Điều đó có nghĩa là tài liệu đang làm rõ rằng việc gọi xây dựng trên một liên kết là giống nhau đang tạo ra một đối tượng mới (gọi .new) và chuyển các khóa ngoại cho đối tượng đó. Các lệnh này đều tương đương:

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

Tôi tin rằng lý do .build tồn tại là Firm.first.clents.new có thể được hiểu là bạn đang tạo một đối tượng quan hệ has_many mới, chứ không phải là một khách hàng thực tế, vì vậy, gọi .build là một cách để làm rõ điều này.


Vì vậy, chúng tương đương. Đó chắc chắn là những gì nó có vẻ. Cảm ơn bạn!
ClosCowboy

5
Điều này LAF không đúng. Hai cái đầu tiên tương đương trong các phiên bản sau của Rails (có vẻ như tại thời điểm đăng chúng không có). NHƯNG, cái cuối cùng có một sự khác biệt đáng kể trong đó Firm.first.clents sẽ không chứa ứng dụng khách mới.
tybro0103

4

buildvs new:

chủ yếu là mới và xây dựng là như nhau nhưng xây dựng đối tượng lưu trữ trong bộ nhớ ,

ví dụ:

cho mới:

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

Để xây dựng:

Firm.first.clients.build

Ở đây khách hàng được lưu trữ trong bộ nhớ, khi lưu công ty, hồ sơ liên quan cũng được lưu.


2

Người mẫu

Tag.new post_id: 1sẽ khởi tạo một Thẻ với post_idtập hợp của nó .

@ model.models.new

@post.tags.buildthực hiện cùng một thẻ ngay lập tức sẽ có @post.tagsngay cả trước khi nó được lưu.

Điều này có nghĩa là @post.savesẽ lưu cả @post và thẻ mới được xây dựng (giả sử: inverse_of được đặt). Điều này thật tuyệt vì Rails sẽ xác nhận cả hai đối tượng trước khi lưu và sẽ không được lưu nếu một trong hai đối tượng không xác thực.

mô hình.new vs mô hình.build

@post.tags.build@post.tags.newtương đương (ít nhất là từ Rails 3.2).


cái này thì 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:sao
ア レ ッ ク
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.