Skip to content

Instantly share code, notes, and snippets.

@bigfive
Created November 28, 2011 09:33
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bigfive/1399762 to your computer and use it in GitHub Desktop.
Save bigfive/1399762 to your computer and use it in GitHub Desktop.
Ruby on Rails. Module to handle 'quantity' attributes by overriding the << and delete methods of the has_many association
class Package < ActiveRecord::Base
has_many :products, :through => :packagings, extend => QuantityAssociation
# ... do stuff
end
module QuantityAssociation
def include_duplicates
return_array = []
through_collection.each do |through|
associate = through.send(reflection_name)
return_array.concat Array.new(through.quantity || 1).fill( associate )
end
return_array
end
def <<(*records)
result = true
load_target if proxy_association.owner.new_record?
transaction do
flatten_deeper(records).each do |record|
existing = get_existing_through record
if existing.present?
existing.increment! :quantity
else
result &&= super(record)
end
end
end
result && self
end
def delete(*records)
transaction do
flatten_deeper(records).each do |record|
existing = get_existing_through record
if existing.present? and existing.quantity.present? and existing.quantity > 1
existing.decrement! :quantity
else
super(record)
end
end
end
end
private
def reflection_name
proxy_association.source_reflection.name
end
def through_source_key
proxy_association.reflection.source_reflection.foreign_key
end
def through_name
proxy_association.reflection.through_reflection.name
end
def through_collection
proxy_association.owner.send through_name
end
def get_existing_through record
through_collection.where("#{through_source_key}" => record.id).try(:first)
end
def flatten_deeper(array)
array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
end
end
#--------
#--------
# Means you can just do things like
package = Package.first
package.products << Product.first
# and if the product is already associated, the 'quantity' column will be
# incremented on the 'packagings' table
@bigfive
Copy link
Author

bigfive commented Nov 28, 2011

The 'get_existing_through' method could well be done simpler. Anyone know a better way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment