Rails에서 캐스케이드 삭제를 설정할 수 있습니까?


88

나는 이것이 아마도 인터넷 어딘가에 있다는 것을 알고 있지만 여기 Stackoverflow에서 답을 찾을 수 없으므로 여기에서 지식 기반을 조금 높일 수 있다고 생각했습니다.

저는 Ruby와 Rails의 초보자이지만 제 회사는 그것에 대해 꽤 투자하고 있으므로 조금 더 자세히 알아 보려고 노력하고 있습니다.

데이터베이스가 아닌 "모델"에서 응용 프로그램을 디자인하는 것에 대한 마음가짐을 바꾸는 것이 어려웠 기 때문에 데이터베이스에서 고전적으로 수행 한 모든 디자인 작업을 대신 Rails 모델.

그래서 내가 나에게 준 가장 최근 작업은 계단식 삭제를 수행하도록 Rails 데이터베이스 모델을 구성하는 방법을 알아내는 것입니다. 이 작업을 수행하는 쉬운 방법이 있습니까? 아니면 MySql로 가서 이것을 설정해야합니까?

답변:


103

: dependent 옵션을 : delete_all로 설정할 수도 있습니다. : delete_all은 모든 하위 레코드를 삭제하는 단일 SQL 문을 실행합니다. 이 때문에 : delete_all을 사용하면 더 나은 성능을 얻을 수 있습니다.

has_many :memberships, dependent: :delete_all

8
설명이 혼란 스럽습니다. 단일 SQL 문이 사용되지만 각 하위 행에 대해 destroy 메소드가 호출되지 않습니다. 이를 위해 destroy_all을 사용해야합니다.
John Topley

@John-편집이 혼란을 없애기를 바랍니다. 지적 해 주셔서 감사합니다.
Mike Breen

26
당신이 사용 사이의 차이를 이해하고 있는지 확인 :delete_all하고 :destroy이에 대한합니다. 둘 다 n데이터베이스에서 하위 멤버십 (삭제 [인용 필요] 및 삭제 (자식에 종속 삭제가있는 경우)에 대한 1 수준 )이 제거되도록하지만 :destroy각 하위 개체를 인스턴스화하고 콜백을 먼저 :delete_all실행하지만 데이터베이스의 SQL DELETE 문. :destroy그 때문에 느리지 만 레코드가 파괴 될 때 콜백을 가질 수 있습니다. 한쪽 끝에서는 Rails를 우회하고 다른 쪽 끝에서는 n ^ x 인스턴스화 가능성.
jstim 2014 년

2
또한 데이터베이스 외래 키를 설정하는 것이 좋습니다. 이렇게하면 한 번의 작업으로 레코드가 삭제됩니다. 내가 게시 한 아래 답변을 참조하십시오.
Hendrik

66

예, 할 수 있습니다. has_many와 같은 관계를 사용하는 경우 이렇게하면됩니다.

has_many :memberships, dependent: :destroy

Dan, 그래서 내 다음 질문은 db migrate 명령을 실행하면 실제로 db에 설정됩니까? 아니면 계단식이 완전히 레일로 처리됩니까?
matt_dev 2008-12-01

예, 레일로 처리됩니다. (그래도 항상 모든 관련 행을 삭제
해야하는지

@Matt-has_many 라인은 모델 클래스에 있어야하며 마이그레이션은이를 추가하지 않습니다.
Gareth

종속 모델에 다른 has_many 관계가있는 경우에도 작동
하므로이

25

제공된 답변과 달리 데이터베이스 수준에서이 작업을 수행하는 것이 좋습니다. 다른 프로세스 또는 다중 스레드 환경이있는 경우 레코드가 제대로 삭제되지 않을 수 있습니다. 또한 데이터베이스 외래 키는 많은 데이터를 삭제할 때 일을 더 빠르게 만듭니다.

제안 된 답변 에서처럼 다음을 수행하십시오.

has_many :memberships, dependent: :delete_all

그러나 foreign_key마이그레이션에서 a 를 설정해야 합니다. 이렇게하면 데이터베이스가 자동으로 레코드를 삭제합니다.

사용자 모델이 있다고 가정하고 멤버십이 삭제 될 때 값을 무효화하려면 다음을 수행하십시오.

add_foreign_key :users, :memberships, on_delete: :nullify

멤버십이 삭제 될 때마다 모든 모델을 삭제할 수도 있습니다.

add_foreign_key :users, :memberships, on_delete: :cascade

그래서 "has_many : memberships, dependent : : delete_all"과 "add_foreign_key : users, : memberships, on_delete : : cascade"를 모두 사용할 수 있습니까? 잘 작동할까요?
Rubycon

2
delete_all모델에서 를 설정할 필요도 없습니다 . 외래 키는 데이터베이스 수준에서 모든 것을 적절하게 삭제합니다.
Hendrik

3
둘 다 할 때 어떤 일이 일어나는지 궁금합니다. 부정적인 영향이 없어야 할 것 같지만 AR과 DB 레벨을 모두 수행하는 이러한 관행에 대해 나쁜 경험을 한 사람이 있습니까?
James Klein

1
데이터베이스 수준은 내가 찾던 것입니다. 이것은 제 생각에 받아 들여진 대답이어야합니다. 다른 것들은 내 쿼리가 표준 ActiveRecord 작업을 고수하는 경우에만 작동하는 것처럼 보입니다.
Brett Beatty

10

delete_all은 하위 레코드에 대한 콜백 (예 : before_destroy 및 after_destroy)을 실행하지 않습니다.


6

계단식 삭제가 실제 데이터베이스 구조에 반영되도록하려면이 플러그인이 원하는 것을 제공 할 수 있습니다.

http://www.redhillonrails.org/foreign_key_migrations.html

마이그레이션에서 이것을 사용하는 형식은 다음과 같습니다.

create_table :orders do |t|
  t.column :customer_id, :integer, :on_delete => :set_null, :on_update => :cascade
  ...
end

5
그 링크는 죽었지 만 이것은 새로운 대안입니다 : github.com/matthuhiggins/foreigner
gdelfino
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.