cách thêm bản ghi vào has_many: thông qua liên kết trong rails


94
class Agents << ActiveRecord::Base
  belongs_to :customer
  belongs_to :house
end

class Customer << ActiveRecord::Base
  has_many :agents
  has_many :houses, through: :agents
end

class House << ActiveRecord::Base
  has_many :agents
  has_many :customers, through: :agents
end

Làm cách nào để thêm vào Agentsmô hình cho Customer?

Đây có phải là cách tốt nhất?

Customer.find(1).agents.create(customer_id: 1, house_id: 1)

Ở trên hoạt động tốt từ bảng điều khiển, tuy nhiên, tôi không biết làm thế nào để đạt được điều này trong ứng dụng thực tế.

Hãy tưởng tượng một biểu mẫu được điền cho khách hàng cũng được lấy house_idlàm đầu vào. Sau đó, tôi có làm như sau trong bộ điều khiển của mình không?

def create 
  @customer = Customer.new(params[:customer])
  @customer.agents.create(customer_id: @customer.id, house_id: params[:house_id])
  @customer.save
end

Nói chung, tôi bối rối không biết làm thế nào để thêm các bản ghi trong has_many :throughbảng?


Bạn sẽ lưu trữ hàm "create" trong bộ điều khiển nào?
Tobias Kolb

Câu trả lời:


162

Tôi nghĩ bạn có thể đơn giản làm điều này:

 @cust = Customer.new(params[:customer])
 @cust.houses << House.find(params[:house_id])

Hoặc khi tạo một ngôi nhà mới cho khách hàng:

 @cust = Customer.new(params[:customer])
 @cust.houses.create(params[:house])

Bạn cũng có thể thêm qua id:

@cust.house_ids << House.find(params[:house_id])

16
FYI: Bạn không thể tạo ngôi nhà được liên kết trừ khi phần tử gốc đã được lưu.
Ricardo Otero

Đó phải là giải pháp thanh lịch nhất cho vấn đề này mà tôi đã gặp. +1 cho bạn.
Daniel Bonnell

@RicardoOtero Tôi đoán chúng ta có thể sử dụng buildistead of create?
Karan

@Mischa tôi nên xử lý lỗi như thế nào nếu House.find (params [: house_id]) là nill .. tôi gặp lỗi TypeMismatch nếu params [: house_id] là nil .. tôi đã sử dụng cứu hộ. nhưng có cách nào tốt hơn .. ??
Vishal

1
Tôi đã quan sát thấy rằng việc sử dụng <<toán tử thực hiện chèn hai lần trong một số trường hợp nhất định. Vì vậy, createphương pháp là cách tốt nhất.
Hoán đổi

77

'Cách tốt nhất' phụ thuộc vào nhu cầu của bạn và những gì bạn cảm thấy thoải mái nhất. Nhầm lẫn xuất phát từ sự khác biệt ActiveRecord của hành vi của các newcreatecác phương pháp và các <<nhà điều hành.

các newPhương pháp

newsẽ không thêm bản ghi liên kết cho bạn. Bạn phải tự xây dựng HouseAgentghi lại:

house = @cust.houses.new(params[:house])
house.save
agent = Agent(customer_id: @cust.id, house_id: house.id)
agent.save

Lưu ý rằng @cust.houses.newHouse.newhiệu quả là như nhau vì bạn cần tạo Agentbản ghi trong cả hai trường hợp.

Người <<điều hành

Như Mischa đã đề cập, bạn cũng có thể sử dụng <<toán tử trên bộ sưu tập. Điều này sẽ chỉ xây dựng Agentmô hình cho bạn, bạn phải xây dựng Housemô hình:

house = House.create(params[:house])
@cust.houses << house
agent = @cust.houses.find(house.id)

các createPhương pháp

createsẽ xây dựng cả hai HouseAgentcác bản ghi cho bạn, nhưng bạn sẽ cần tìm Agentmô hình nếu bạn định trả lại mô hình đó cho chế độ xem hoặc api của mình:

house = @cust.houses.create(params[:house])
agent = @cust.agents.where(house: house.id).first

Lưu ý cuối cùng, nếu bạn muốn các ngoại lệ được nâng lên khi tạo, hãy housesử dụng các toán tử bang thay thế (ví dụ new!create!).


2
Có nên agent = @cust.houses.find(house.id)đọc dòng agent = @cust.agents.find(house.id)thay thế không? Các agentbiến trong "Phương pháp mới" khác với agenttrong các ví dụ sau. Có thể tạo ra một số nhầm lẫn cho những người làm việc với các thuộc tính bổ sung trên bảng tham gia.
vaughan

bạn có thể xây dựng trên lấy dữ liệu từ các đại lý bảng doanh mà không cần phải N + 1 lỗi ví dụ hiển thị tất cả các ngôi nhà và tương ứng với các đại lý cho khách hàng được
Ankita.P

6

Một cách khác để thêm liên kết là sử dụng các cột khóa ngoại:

agent = Agent.new(...)
agent.house = House.find(...)
agent.customer = Customer.find(...)
agent.save

Hoặc sử dụng các tên cột chính xác, chuyển ID của bản ghi được liên kết thay vì bản ghi.

agent.house_id = house.id
agent.customer_id = customer.id
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.