Default Data Templates

In my database, I have a lot of duplicated data between entries. For
example, I might have a database of foods where Meats is the parent
object and Cheeseburger is one of its children.

o=Food.New
o.name = “Meats”
o.text = “This food is really unhealthy…lots of text”
o.category = “Meats”
o.save

p=Food.New
p.parent = o.id
p.name = “Cheeseburger”
p.save

If unpopulated, I’d like the parent’s data to be accessed. I
implemented this inside the model on an attribute-by-attribute basis,
but this seems to stink of bad design, since every time I add a new
field, I have to write duplicate code that checks if the attribute is
empty.

Any ideas would be greatly appreciated.

On 10 Jun 2008, at 04:41, glenviewjeff wrote:

p=Food.New
p.parent = o.id
p.name = “Cheeseburger”
p.save

If unpopulated, I’d like the parent’s data to be accessed. I
implemented this inside the model on an attribute-by-attribute basis,
but this seems to stink of bad design, since every time I add a new
field, I have to write duplicate code that checks if the attribute is
empty.

you could do something like

class << self
def attr_parent *names
names.each do |name|
define_method name do
self.read_attribute(name) || parent.send(name)
end
end
end
end

then you can stick
attr_parent :name, :text, … in your model (try and pick a better
name than me) and it will call the parent object if the attribute is
nil (if you also want this to happen on a empty string just change the
conditions. You could also stick this in a module and extend
ActiveRecord::Base with it, and then all ActiveRecord subclasses will
be able to use it

Fred

Thank you very much Fred. It took me some time to learn Ruby’s OO
implementation well enough to understand your post, but I was
successful.

For anyone with similar problems, I’ve pasted my code below.
Incidentally, my code smells bad again, in that I am explicitly
testing for specific classes (i.e., string or not,) and I would think
this would be better handled by extending the class for each data type
(string, etc.) Any thoughts?

Thanks,
Jeff

class FoodItem < ActiveRecord::Base
class << self
def attr_parent *names
names.each do |name|
define_method name do
self.read_attribute( name )
if self.read_attribute( name ).is_a? String
if self.read_attribute( name ).empty? && !
self.DuplicateOf.nil?
FoodItem.find(self.DuplicateOf).send(name)
else
self.read_attribute( name )
end
else
self.read_attribute(name) ||
FoodItem.find(self.DuplicateOf).send(name)
end
end
end
end
end

attr_parent :FoodType, :FoodPrice

end

On 14 Jun 2008, at 20:37, glenviewjeff wrote:

I’m not entirely sure what you’re doing there, but it sounds like you
could simplify it to

if self.read_attribute( name ).blank?
FoodItem.find(self.DuplicateOf).send(name)
else
self.read_attribute( name )
end
(blank? returns true for nil, an empty string, an empty array etc…

You might also want to use an association (so that the find is cached
rather than hitting the database each time. It’s also ruby convention
that method names be underscored, not camelcased (which is used for
constants, eg class names), as it is it makes your code look very odd.

Fred