How to Set Up Cascade Deleting in Rails

Can I set up Cascade deleting in Rails?

you can also set the :dependent option to :delete_all. :delete_all will issue a single SQL statement to delete all child records. because of this using :delete_all may give you better performance.

has_many :memberships, dependent: :delete_all

Adding cascade deletion in a rails

drop it and add it again (it's an index, no information is lost).

class ModifyTreeRefFromDogs < ActiveRecord::Migration
def change
remove_foreign_key "dog", "trees"
add_foreign_key "dog", "trees", on_delete: :cascade
end
end

Note: this seems to be a good reference for foreign keys in rails and includes exactly the on_delete code you tried: Foreign Keys in Rails 4.2

Rails: delete cascade vs dependent destroy

It really depends on the behavior you want. In case 1, destroy will be called on each associated order, and therefor so will the ActiveRecord callbacks. In case 2, these callbacks are not triggered, but it will be way faster and guarantees referential integrity.

In an application's infancy, I'd recommend going with :dependent => :destroy because it lets you develop in a way that is independent of the database. Once you start to scale, you should start doing it in the database for performance/integrity reasons.

How to add column as foreign key with cascade delete in rails

Solution is ref_name should be singular

 add_reference(:usages, :product, foreign_key: { on_delete: :cascade })

Cascade delete in Ruby ActiveRecord models?

Yes. On a Rails' model association you can specify the :dependent option, which can take one of the following three forms:

  • :destroy/:destroy_all The associated objects are destroyed alongside this object by calling their destroy method
  • :delete/:delete_all All associated objects are destroyed immediately without calling their :destroy method
  • :nullify All associated objects' foreign keys are set to NULL without calling their save callbacks

Note that the :dependent option is ignored if you have a :has_many X, :through => Y association set up.

So for your example you might choose to have a post delete all its associated comments when the post itself is deleted, without calling each comment's destroy method. That would look like this:

class Post < ActiveRecord::Base
validates_presence_of :body, :title
has_many :comments, :dependent => :delete_all
end

Update for Rails 4:

In Rails 4, you should use :destroy instead of :destroy_all.

If you use :destroy_all, you'll get the exception:

The :dependent option must be one of [:destroy, :delete_all, :nullify,
:restrict_with_error, :restrict_with_exception]

Option for Cascade Delete for References or On Delete

This should work

create_table :childs do |t|
t.references :parent, index: true, foreign_key: {on_delete: :cascade}
t.string :name

t.timestamps null: false
end

According to ActiveRecord::ConnectionAdapters::TableDefinition#references, if a hash is specified on the foreign_key option, it is directly passed down into the foreign_key method.

source:

foreign_key(col.to_s.pluralize, foreign_key_options.is_a?(Hash) ? foreign_key_options : {}) if foreign_key_options

Is it possible to cascade active record deletion in batches?

You really just need to setup the foreign keys to cascade and Postgres will take care of deleting all the way down the line. Since this is implemented on the database layer it does not matter how you trigger the delete from Rails.

class CreateCountries < ActiveRecord::Migration[6.0]
def change
create_table :countries do |t|
t.string :name
t.timestamps
end
end
end

class CreateStates < ActiveRecord::Migration[6.0]
def change
create_table :states do |t|
t.string :name
t.belongs_to :country, null: false, foreign_key: {on_delete: :cascade}
t.timestamps
end
end
end

class CreateCities < ActiveRecord::Migration[6.0]
def change
create_table :cities do |t|
t.string :name
t.belongs_to :state, null: false, foreign_key: {on_delete: :cascade}
t.timestamps
end
end
end

Models:

class Country < ApplicationRecord
has_many :states
has_many :cities, through: :states
end

class State < ApplicationRecord
belongs_to :country
has_many :cities
end

class City < ApplicationRecord
belongs_to :state
has_one :country, through: :state
end

Passing spec:

require 'rails_helper'

RSpec.describe Country, type: :model do
describe "cascading delete" do
let!(:country){ Country.create }
let!(:state){ country.states.create }
let!(:city){ state.cities.create }

it "deletes the states" do
expect {
country.delete
}.to change(State, :count).from(1).to(0)
end

it "deletes the cities" do
expect {
Country.delete_all
}.to change(City, :count).from(1).to(0)
end
end
end

If you are using .each_with_batches or not here is kind of irrelevant here. Anything that creates a DELETE FROM countries query is going to fire that database trigger. Unless you really need to evaluate if each parent should be deleted in Rails you should just be able to do:

Country.where(evil: true).delete_all

This is going to be far more efficient then .find_each as you're just doing one SQL query. If you iterate through the records you're doing one DELETE FROM coutries WHERE id = ? query per row and since its blocking Rails has to wait for the round trip to the db.

How do I create a foreign key with a cascading delete constraint in my Rails 5 migration?

Seems like that ReferenceDefinition doesn't accept on_delete option. You can specify on delete with add_foreign_key:

class CreateSearchCodeTable < ActiveRecord::Migration[5.0]
def change
create_table :search_codes do |t|
t.string :code
t.references :address, type: :string, index: true
t.index ["code"], name: "index_search_codes_on_code", unique: true, using: :btree
end

add_foreign_key :search_codes, :addresses, on_delete: :cascade
end
end


Related Topics



Leave a reply



Submit