has_many에 레코드를 추가하는 방법 : rails의 연관을 통해


97
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

Agents모델에 Customer어떻게 추가 합니까?

이것이 최선의 방법입니까?

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

위의 내용은 콘솔에서 잘 작동하지만 실제 응용 프로그램에서이를 달성하는 방법을 모르겠습니다.

house_id입력으로 도 사용되는 고객을 위해 양식이 채워져 있다고 상상해보십시오 . 그런 다음 컨트롤러에서 다음을 수행합니까?

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

전반적으로 has_many :through테이블 에 레코드를 추가하는 방법에 대해 혼란 스럽 습니까?


어떤 컨트롤러에 "create"기능을 저장 하시겠습니까?
Tobias Kolb

답변:


166

나는 당신이 간단히 할 수 있다고 생각합니다.

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

또는 고객을 위해 새 집을 만들 때 :

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

ID를 통해 추가 할 수도 있습니다.

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

16
참고 : 부모가 이미 저장되어 있지 않으면 연결된 집을 만들 수 없습니다.
Ricardo Otero 2014

이것이 제가 본이 문제에 대한 가장 우아한 해결책이어야합니다. 당신을 위해 +1.
Daniel Bonnell

@RicardoOtero 나는 우리가 buildistead를 사용할 수 있다고 생각 create합니까?
Karan

@Mischa House.find (params [: house_id])가 nill 인 경우 어떻게 오류를 처리해야합니까 .. params [: house_id]가 nil 인 경우 TypeMismatch 오류가 발생했습니다 .. 이미 구조를 사용하고 있습니다. 하지만 더 나은 방법이 있습니까 .. ??
Vishal

1
<<연산자 를 사용하면 특정 경우에 두 번 삽입 하는 것을 관찰했습니다 . 그래서 그 create방법이 최선의 방법입니다.
스와핑

78

'가장 좋은 방법'은 귀하의 필요와 가장 편안한 느낌에 따라 다릅니다. ActiveRecord의 newcreate메서드 동작 과 <<연산자 의 차이로 인해 혼란이 발생 합니다 .

new방법

new연결 레코드를 추가하지 않습니다. 직접 작성 House하고 Agent기록 해야합니다 .

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

참고 그 @cust.houses.newHouse.new당신이 작성해야하기 때문에 효율적으로 동일한 Agent두 경우 모두에서 기록을.

<<운영자

Mischa가 언급했듯이 <<컬렉션 에서 연산자를 사용할 수도 있습니다 . 이렇게하면 Agent모델 만 빌드되며 모델을 빌드해야합니다 House.

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

create방법

createHouseAgent레코드를 모두 빌드 하지만 Agent뷰 또는 API로 반환 하려면 모델 을 찾아야합니다 .

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

마지막으로, 생성 할 때 예외가 발생 house하도록하려면 bang 연산자를 대신 사용하십시오 (예 : new!and create!).


2
대신 줄을 agent = @cust.houses.find(house.id)읽어야 agent = @cust.agents.find(house.id)합니까? agent"새 메소드" 의 변수 agent는 후자의 예와 다릅니다 . 조인 테이블에서 추가 속성으로 작업하는 사람들에게 혼동을 줄 수 있습니다.
본입

당신은 주어진 고객을 위해 에이전트를 모두에게 주택을 표시하는 N + 1 버그의 예를 가지고 대응하지 않고 공동 테이블 에이전트로부터 데이터를 검색에 정교한 수
Ankita.P

6

연결을 추가하는 또 다른 방법은 외래 키 열을 사용하는 것입니다.

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

또는 레코드 대신 연관된 레코드의 ID를 전달하여 정확한 열 이름을 사용하십시오.

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