lib/active_repository/associations.rb
# Defines the relations between ActiveRepository objects.
#
# Author:: Caio Torres (mailto:efreesen@gmail.com)
# License:: GPL
module ActiveRepository
module Associations
def self.included(base)
base.extend Methods
end
module Methods
# Defines "has many" type relation between ActiveRepository objects
def has_many(association_id, options = {})
define_method(association_id) do
options = {
class_name: association_id.to_s.classify,
foreign_key: self.class.to_s.foreign_key
}.merge(options)
foreign_key = options[:foreign_key]
klass = options[:class_name].constantize
klass.where(foreign_key => id)
end
end
# Defines "has one" type relation between ActiveRepository objects
def has_one(association_id, options = {})
options = {
class_name: association_id.to_s.classify,
foreign_key: self.to_s.foreign_key
}.merge(options)
has_one_methods(association_id, options)
end
# Defines "belongs to" type relation between ActiveRepository objects
def belongs_to(association_id, options = {})
options = {
class_name: association_id.to_s.classify,
foreign_key: association_id.to_s.foreign_key
}.merge(options)
field options[:foreign_key].to_sym
belongs_to_methods(association_id, options)
end
private
def has_one_methods(association_id, options)
define_has_one_method(association_id, options)
define_has_one_setter(association_id, options)
define_has_one_create(association_id, options)
end
def belongs_to_methods(association_id, options)
define_belongs_to_method(association_id, options)
define_belongs_to_setter(association_id, options)
define_belongs_to_create(association_id, options)
end
def define_has_one_method(association_id, options)
define_method(association_id) do
foreign_key = options[:foreign_key]
klass = options[:class_name].constantize
klass.where(foreign_key => self.id).first
end
end
def define_has_one_setter(association_id, options)
define_method("#{association_id}=") do |object|
primary_key = self.send(self.class.primary_key)
foreign_key = options[:foreign_key]
association = self.send(association_id)
association.update_attribute(foreign_key, nil) if association
object.update_attribute(foreign_key, primary_key) if object
end
end
def define_has_one_create(association_id, options)
define_method("create_#{association_id}") do |attributes|
primary_key = self.send(self.class.primary_key)
foreign_key = self.class.to_s.foreign_key
association = self.send(association_id)
klass = options[:class_name].constantize
association.update_attribute(foreign_key, nil) if
self.send("#{association_id}=", nil)
klass.create(attributes.merge(foreign_key => primary_key))
end
end
def define_belongs_to_method(association_id, options)
define_method(association_id) do
klass = options[:class_name].constantize
foreign_key = send(options[:foreign_key])
klass.where(klass.primary_key => foreign_key).first
end
end
def define_belongs_to_setter(association_id, options)
define_method("#{association_id}=") do |new_value|
attributes.delete(association_id.to_sym)
send("#{options[:foreign_key]}=", (new_value.try(:id) ? new_value.id : new_value))
end
end
def define_belongs_to_create(association_id, options)
define_method("create_#{association_id}") do |attributes|
klass = options[:class_name].constantize
object = klass.create(attributes)
self.update_attribute(options[:foreign_key], object.id)
object
end
end
end
end
end