0

There is a join table with three columns: id, product_a_id, product_b_id

class ProductConnection < ActiveRecord::Base
  belongs_to :product_a, class_name: :Product
  belongs_to :product_b, class_name: :Product    
end

I would like to filter the table by a specific product regardless in which column the product id is contained. How can I write a named scope which respects that a product can be nil? The following draft is inspired by a post by Zack Holman though it does not work:

scope :find_by_product, \
  lambda {|p| p.nil? ? { \
    where(["product_a_id = ? OR product_b_id = ?", p.id, p.id]) : {} \
  }

Then I would like to know how I can delete all products returned in the ActiveRecord::Relation?

JJD
  • 50,076
  • 60
  • 203
  • 339

1 Answers1

1

It sounds like the issue is with how to make your find_by_product scope work when the passed in product is nil? I think your curly braces are a little mixed up. Either way, here's how I'd write it in case this helps:

ProductConnection

scope :for_product, ->(product) {
  if product_id = product.try(:id)
    where(arel_table[:product_a_id].eq(product_id).
            or(arel_table[:product_b_id].eq(produt_id))
  end
}

Then, once that works, you can just call destroy_all on the scope to destroy all the records.

ProductConnection.for_product(my_product).destroy_all

There is also delete_all, which you can use in the same way, if you really don't want the ActiveRecord callbacks included with destroy.

pdobb
  • 17,688
  • 5
  • 59
  • 74
  • If this works for you I'm happy to explain more about the syntax used if needed. – pdobb Sep 08 '13 at 21:47
  • Looks nice, however it returns all entries of the join table when I pass `nil` to the scope. – JJD Sep 09 '13 at 18:47
  • @JJD, what would you like to be returned when passing `nil` to the scope? When passing `nil` would you like it to return all entires where `product_a_id` is `nil` or `product_b_id` is `nil`? If so, remove the `if` adn the `end` (keeping the `product_id = product.try(:id)`. Then, if `product` is `nil` the `product_id` local var will be `nil` and the rest should play itself out. – pdobb Sep 10 '13 at 03:49
  • I am not entirely sure. But imagine you concatenate another scope while the passed `product` is nil. What would you expect to happen? For instance if you run `delete_all` on the result it would be fatal if all products are deleted. – JJD Sep 10 '13 at 07:51
  • 1
    Hrm. So maybe you want it to return no results if the passed in product was `nil`? Personally, I would expect that a passed in `nil` product would do no filtering. I.e. it wouldn't limit my result set any. Just like if I added a scope like `for_user(nil)` it should return all items for the user nil, which doesn't exist, so just return all. Maybe you just need to ensure that the product you're passing in isn't `nil`? In that case you could use a class method instead of a scope. Then you could raise an exception if `product` was passed in as `nil`. – pdobb Sep 10 '13 at 17:14