refactorit-logo

Using custom scope in Rails association

Feb 05, 2016

I came across a situation that I needed a custom scope in an 5 association, something that is unusual. It can help a lot, and here’s how.

Scoped associations

On a project that I’m working on, BidProduct model delegates photo_url to a Product model. The Product model uses Paranoia gem for soft delete.

Simplified a bit, it look like this:

class BidProduct < ActiveRecord::Base
  belongs_to :product

  delegate :photo_url, to: :product
end
class Product < ActiveRecord::Base
  acts_as_paranoid
end

The problem occurs when someone deletes Product object. Calling photo_url method in BidProduct raises Module::DelegationError exception. Desired functionality is to keep BidProduct record and show it’s photo even when original Product is deleted.

Luckily, Paranoia gem provides with_deleted scope which includes deleted records in the results. Less known feature in Rails associations is passing scope block to it. When scope block is passed in association, it is applied when the connected model is accessed.

Combining these two we can write our BidProduct class like this:

class BidProduct < ActiveRecord::Base
  belongs_to :product, -> { with_deleted }

  delegate :photo_url, to: :product

end

Now photo_url on the BidProduct object is delegated to the Product object even when it’s soft deleted.

Any other standard querying method can be used inside the scope block. You can check more about it in Scopes for belongs_to section of Rails guides.