sickrandir
sickrandir

Reputation: 123

Rails: delete on scoped association behaves differently than just delete from the association

I have a project based on Rails 4.2.

I have defined two models like this:

class Option < ActiveRecord::Base
    has_many :item_options
    has_many :items, through: :item_options, source: :item 

    scope :materials, -> { where(category: 'material') }
    scope :types, -> { where(category: 'type') }

class Item < ActiveRecord::Base
    has_many :item_options
    has_many :options, through: :item_options

I'm not able to delete association's join records through the scopes of the Option model.

If I do:

Item.first.options.materials.delete_all

the executed query is:

DELETE FROM "options" WHERE "options"."id" IN (SELECT "options"."id" FROM "options" INNER JOIN "item_options" ON "options"."id" = "item_options"."option_id" WHERE "item_options"."item_id" = $1 AND "options"."category" = $2)

That removes records from the Option model and it's not what I was expecting.

If I try to delete association records without using a scope, like this:

Item.first.options.delete_all

that correctly executes the query:

DELETE FROM "item_options" WHERE "item_options"."item_id" = $1

Effectively removing only the join records.

Why does delete behave differently if called through a scope?

(edited, contained a pasting error with old name LabelItem for one of the models)

Upvotes: 1

Views: 270

Answers (1)

Rodrigo
Rodrigo

Reputation: 4802

When you call the method materials in the options relation it returns an Option relation instance. That's why it won't work.

It might work:

class Item < ActiveRecord::Base
    has_many :item_options
    has_many :options, through: :item_options
    has_many :material_options, -> { materials }, through: :item_options, source: :option

Then:

Item.first.material_options.delete_all

Upvotes: 1

Related Questions