Tôi có thể thiết lập xóa Cascade trong Rails không?


88

Tôi biết điều này có thể là trên Internet ở đâu đó nhưng tôi không thể tìm thấy câu trả lời ở đây trên Stackoverflow vì vậy tôi nghĩ tôi có thể nâng cao cơ sở kiến ​​thức ở đây một chút.

Tôi là một người mới làm quen với Ruby and Rails nhưng công ty của tôi đang đầu tư khá nhiều vào nó nên tôi đang cố gắng tìm hiểu nó một cách chi tiết hơn.

Thật khó để tôi thay đổi suy nghĩ của mình để thiết kế một ứng dụng từ "mô hình" thay vì từ cơ sở dữ liệu, vì vậy tôi đang cố gắng tìm ra cách thực hiện tất cả công việc thiết kế mà tôi đã từng thực hiện trong Cơ sở dữ liệu trong Thay vào đó, mô hình đường ray.

Vì vậy, nhiệm vụ gần đây nhất mà tôi đã giao cho mình là tìm ra cách cấu hình mô hình cơ sở dữ liệu Rails để thực hiện xóa theo tầng? Có một cách dễ dàng để làm điều này? Hay tôi sẽ phải vào MySql và thiết lập điều này?

Câu trả lời:


103

bạn cũng có thể đặt tùy chọn: phụ thuộc thành: delete_all. : delete_all sẽ đưa ra một câu lệnh SQL duy nhất để xóa tất cả các bản ghi con. vì điều này bằng cách sử dụng: delete_all có thể mang lại cho bạn hiệu suất tốt hơn.

has_many :memberships, dependent: :delete_all

8
Lời giải thích của bạn thật khó hiểu. Một câu lệnh SQL duy nhất sẽ được sử dụng, nhưng phương thức hủy sẽ không được gọi cho mỗi hàng con. Bạn phải sử dụng kill_all cho điều đó.
John Topley

@John - hy vọng các chỉnh sửa làm rõ sự nhầm lẫn. cảm ơn vì đã chỉ ra điều đó.
Mike Breen

26
Đảm bảo rằng bạn hiểu sự khác biệt giữa việc sử dụng :delete_all:destroycho việc này. Cả hai đều sẽ khiến tư cách thành viên con (1 cấp để xóa [cần dẫn nguồn] và nhủy (nếu con của họ có người hủy phụ thuộc)) bị xóa khỏi cơ sở dữ liệu, nhưng :destroysẽ khởi tạo từng đối tượng con và chạy bất kỳ lệnh gọi lại nào trước, trong khi :delete_allsẽ trực tiếp chạy Câu lệnh SQL DELETE trong cơ sở dữ liệu. :destroyvì điều đó chậm hơn, nhưng nó cho phép bạn gọi lại khi bản ghi bị hủy. Phá vỡ các đường ray ở một đầu và khả năng tạo n ^ x ở đầu kia.
jstim

2
Tôi cũng đề nghị thiết lập các khóa ngoại cơ sở dữ liệu. Bằng cách đó, các bản ghi được xóa bằng một thao tác. Xem câu trả lời dưới đây tôi đã đăng.
Hendrik

66

Vâng, bạn có thể, nếu bạn đang sử dụng một mối quan hệ như has_many, bạn chỉ cần làm điều này

has_many :memberships, dependent: :destroy

Dan, Vì vậy, tôi đoán câu hỏi tiếp theo của tôi là nếu tôi chạy một lệnh di chuyển db thì lệnh đó có thực sự được thiết lập trong db không? Hay việc xếp tầng hoàn toàn được xử lý bằng đường ray?
matt_dev

Có, nó được xử lý bởi đường ray. (Tuy nhiên, hãy đảm bảo rằng bạn thực sự luôn cần xóa mọi hàng liên quan.)
Stein G. Strindhaug

@Matt - dòng has_many phải nằm trong lớp mô hình của bạn, quá trình di chuyển sẽ không thêm dòng đó cho bạn.
Gareth

Tôi thích giải pháp này hơn vì nó cũng hoạt động nếu mô hình phụ thuộc có một quan hệ has_many khác
tpei

25

Trái ngược với câu trả lời đã cung cấp, tôi thực sự khuyên bạn nên làm điều này ở cấp độ cơ sở dữ liệu. Trong trường hợp bạn có các quy trình khác nhau hoặc môi trường đa luồng, có thể xảy ra trường hợp các bản ghi không được xóa đúng cách. Hơn nữa, khóa ngoại của cơ sở dữ liệu giúp mọi thứ nhanh hơn khi xóa nhiều dữ liệu.

Giống như trong câu trả lời gợi ý, hãy làm điều này:

has_many :memberships, dependent: :delete_all

Tuy nhiên, hãy đảm bảo thiết lập một foreign_keytrong một lần di chuyển. Bằng cách đó, cơ sở dữ liệu sẽ tự động xóa các bản ghi cho bạn.

Để vô hiệu hóa các giá trị khi thành viên bị xóa, giả sử bạn có mô hình người dùng:

add_foreign_key :users, :memberships, on_delete: :nullify

Bạn cũng có thể xóa tất cả các mô hình bất cứ khi nào tư cách thành viên bị xóa

add_foreign_key :users, :memberships, on_delete: :cascade

Vậy tôi có thể sử dụng cả "has_many: Memberhips, depend:: delete_all" và "add_foreign_key: users,: Memberhips, on_delete:: cascade" không? Nó sẽ hoạt động tốt?
Rubycon

2
Bạn thậm chí sẽ không cần thiết lập delete_alltrong mô hình. Khóa ngoại sẽ đảm nhiệm việc xóa mọi thứ đúng cách cho bạn trên cấp cơ sở dữ liệu.
Hendrik

3
Tôi tò mò về những gì sẽ xảy ra khi bạn làm cả hai. Có vẻ như nó sẽ không có tác động tiêu cực nhưng có ai đã có trải nghiệm tồi tệ với việc thực hiện cả cấp AR và DB này không?
James Klein

1
Mức cơ sở dữ liệu là những gì tôi đang tìm kiếm. Đây nên là câu trả lời được chấp nhận theo ý kiến ​​của tôi. Những cái khác dường như chỉ hoạt động nếu các truy vấn của tôi tuân theo các hoạt động ActiveRecord tiêu chuẩn.
Brett Beatty,

10

Chỉ cần lưu ý rằng delete_all sẽ không thực thi bất kỳ lệnh gọi lại nào (như before_destroy và after_destroy) trên các bản ghi con.


6

Có vẻ như plugin này có thể cung cấp cho bạn những gì bạn đang tìm kiếm nếu bạn muốn các lần xóa theo tầng được phản ánh trong cấu trúc cơ sở dữ liệu thực tế:

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

Định dạng để sử dụng điều này trong quá trình di chuyển sẽ giống như sau:

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

5
Liên kết là chết nhưng đây là một sự thay thế mới hơn: github.com/matthuhiggins/foreigner
gdelfino
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.