Search code examples
ruby-on-rails-4arel

how to create a scope of elements not yet in many to many relationship?


I have created a "many to many" relationship using a has_many :through join table.

class ProductType < ActiveRecord::Base
  has_many :assemblies
  has_many :components, through: :assemblies
end

class Assembly < ActiveRecord::Base
  belongs_to :product_type
  belongs_to :component
end

class Component < ActiveRecord::Base
  has_many :assemblies
  has_many :product_types, through: :assemblies
end

From the complete list of components, I can select a few and add them to the product_type but I should only be allowed to add them once, so the list of components to add from, should only show the components that have NOT yet been added.

I currently have it working with 1) the list of already added components

@product_type.components

2) the list of not yet added ones

Component.all - @product_type.components

This works, but, I would like to create a scope on the components model so that something like

@product_type.components.addable

would generate that second list of not yet added components.

Is this possible? If yes, what would the code be on the components model? or would it go in ProductType? (I havent found anything that works) Also, is there a name for this list of not yet added components? Would it be a "right outer join"? if not, what?

thanks


Solution

  • It is definitely possible. Below is a snippet that shows a scope which should be added to the component model

    scope :addable_to_product_type, -> (product_type) { joins("LEFT JOIN assemblies ON assemblies.component_id = components.id AND assemblies.product_type_id = #{product_type.id}").where("assemblies.component_id IS NULL") }
    

    Usage would be something like this:

    Component.addable_to_product_type(@product_type)