Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Failed attempt at a Logical ActiveRecord layer
# modeled off the Physical / Service / Logical layers
# advocated by http://enterpriserails.chak.org/full-text/chapter-3-organizing-with-modules
module Logical
class ARModelName
PHYSICAL = ARModel
attr_accessor :physical
private :physical
def initialize(physical)
@physical = physical.is_a?(PHYSICAL) ? physical : PHYSICAL.new
end
# first choice way to delegate attributes to PHYSICAL
# require 'forwardable'
# extend Forwardable
# def_delegators :@physical, :create, :create!
# def_delegators :@physical, :email, :email=, :normalized_email, :normalized_email=, :create!
#
# other possible ways to delegate attributes, for consideration
# delegate :email, :email=, :normalized_email, :normalized_email=, :to => @physical #active_support
# [:email, :normalized_email].each do |attribute|
# define_delegated_attribute(attribute)
# end
#
# Pass along the method to @physical if it responds_to? the method
# if so, define the method to avoid another method missing call, and call the method on @physical
# delegate :create!, :to => :@physical.class #active_support
# delegating specified PHYSICAL class methods
class << self
# delegate :create!, :to => PHYSICAL
[:create!, :create].each do |method|
define_method(method) do |*args|
result = PHYSICAL.send(method, *args)
if result.is_a?(PHYSICAL)
new_result = new(result)
new_result
else
result
end
end
end
end
# delegate all physical attributes, and define methods for them here as needed
def method_missing(method, *args, &block)
attribute_name = method.to_s[/^[^?!=]+/]
if PHYSICAL.column_names.include?(attribute_name)
define_delegated_attribute(attribute_name)
@physical.send(method, *args, &block)
elsif delegated_ar_methods.include?(method)
define_ar_method(method)
@physical.send(method, *args, &block)
else
super
end
end
def delegated_ar_methods
[:destroy, :save, :save!]
end
def define_ar_method(method)
class_eval do
define_method(method) do |*args,&block|
@physical.send(method,*args,&block)
end
end
end
def define_delegated_attribute(attribute)
# accessible attributes
unless PHYSICAL.accessible_attributes.include?(attribute.to_s)
class_eval do
define_method(attribute) do
@physical.attribute
end
end
# read only attributes
unless PHYSICAL.readonly_attributes.include?(attribute.to_s)
attribute_setter = "#{attribute}=".to_sym
class_eval do
define_method(attribute_setter) do |new_attribute|
@physical.send(attribute_setter, new_attribute)
end
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.