class Publication < ActiveRecord::Base
def publisher_name
self.publisher.name
end
def publisher_name=(name)
self.publisher = Publisher.find_or_create_by_name(name.strip) unless name.blank?
end
def organization_name
self.organization.name
end
def organization_name=(name)
self.organization = Organization.find_or_create_by_name(name.strip) unless name.blank?
end
end
Refactorings
No refactoring yet !
Spreelanka
November 20, 2008, November 20, 2008 15:12, permalink
no doubt there is a better or faster way to do this.
there is certainly a shorter way to do this, but it's much slower.
I didn't write that version bc I can't remember the name of the method used to implement it. Something like Object#no_method.
class Publication < ActiveRecord::Base
def publisher_name
self.publisher.name
end
def publisher_name=(name)
how_i_set_stuff!(Publisher,name)
end
def organization_name
self.organization.name
end
def organization_name=(name)
how_i_set_stuff!(Organization,name)
end
protected
def how_i_set_stuff!(obj,name)
self.send(obj.to_s.downcase)=obj.find_or_create_by_name(name.strip) unless name.blank?
end
end
Josh N
November 21, 2008, November 21, 2008 03:08, permalink
This solution may be overkill if u only do this for one model. If you need it in many models in might be worth DRYing up the code like the way attr_accessor works
# a module that code gens the attributes
module ChildAccessor
def attr_child_accessor(obj,attr_name)
attr_name = attr_name.to_s
class_name = obj.name.downcase
method_name = "#{class_name}_#{attr_name.to_s}"
class_eval <<-end_eval
def #{method_name}
self.#{class_name}.#{attr_name}
end
def #{method_name}=(#{attr_name})
unless #{attr_name}.blank?
self.#{class_name} =
#{obj.name}.find_or_create_by_#{attr_name}(#{attr_name}.strip)
end
end
end_eval
end
end
# in config/environment.rb
ActiveRecord::Base.extend ChildAccessor
class Publication < ActiveRecord::Base
attr_child_accessor Publisher, :name
attr_child_accessor Orginization, :name
end
Josh N
November 21, 2008, November 21, 2008 05:55, permalink
removed string based class_eval in favor of define_method.. shorter code :)
module ChildAccessor
def attr_child_accessor(obj,attr_name)
child_name = obj.name.downcase
method_name = "#{child_name}_#{attr_name.to_s}"
class_eval do
define_method method_name do
self.send(child_name).send(attr_name)
end
define_method "#{method_name}=" do |name|
self.send("#{child_name}=", obj.send("find_or_create_by_#{attr_name}", name.strip)) unless name.blank?
end
end
end
end
ActiveRecord::Base.extend ChildAccessor
class Publication < ActiveRecord::Base
attr_child_accessor Publisher, :name
attr_child_accessor Orginization, :name
end
Adam
November 21, 2008, November 21, 2008 06:12, permalink
module NameAssociation
def self.extended(object)
object.instance_eval(<<-EOS, '(__NAME_ASSOCIATION__)', 1)
def #{object.proxy_owner.to_s.downcase}_name=(name)
find_or_create_by_name(name)
end
EOS
end
end
class Publication < ActiveRecord::Base
has_one :publication, :extend => NameAssociation
has_one :organization, :extend => NameAssociation
delegate :name, :name=, :to => :publication, :prefix => true
delegate :name, :name=, :to => :organization, :prefix => true
end
My Publication class has a few very similar virtual attributes. Is there any way to unite their setter and getter methods?