Forum: Ruby on Rails Inheriting data from one model to another

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Simon King (Guest)
on 2006-04-11 01:10
(Received via mailing list)
Hello

I've been struggling with something for hours that I thought would be
a simple job. Hopefully somebody can shed some light on what I'm
trying to do :o)

First of all I'll explain what I'm trying to achieve. In a store
application I want to have products and product variations. A product
variation should inherit all of its properties from product unless the
property is defined specifically for the product variation.

Here's how I've tried to implement this: I have a simple Product model
that has various properties such as name and price. I also have
another model, ProductVariation that extends Product using single
table inheritance. ProductVariation adds a belongs_to relationship
that stores the "parent product" - i.e. the one the ProductVariation
overrides.

I've managed to get attributes working correctly - if I call
variation.price it uses method_missing() and send() to decide which
value to return.

ProductVariation looks like this:

class ProductVariation < Product
  belongs_to :parent_product,
             :class_name => "Product",
             :foreign_key => "parent_id"

  @@generate_read_methods = false # turn off generating read_methods
otherwise method_missing won't get called more than once

  # intercept calls to read attributes. If this instance has
  # a value return it, otherwise escalate the call to the parent_product
  def method_missing(method_id, *args, &block)
    method_name = method_id.to_s
    if @attributes.include?(method_name)
      if !read_attribute(method_name).nil?
        puts "Returning #{method_name}"
        return read_attribute(method_name)
      elsif @parent_product
        puts "Escalating #{method_name}"
        return @parent_product.send(method_id, *args, &block)
      end
    end
    puts "Passing thru #{method_name}"
    super
  end
end

My problem is that unless I use the association (by calling
variation.parent_product) before accessing any properties,
@parent_product is nil and the escalation process fails. Is there a
way around this that works inside the model?

I would also like to be able to escalate calls to associations, so if
Product has_many :images, calling variation.images would return its
parent's images unless is had its own set of images.

I hope I've explained this well enough, I'm pretty stumped by it.

Regards,
Simon
This topic is locked and can not be replied to.