Search code examples
ruby-on-railsruby-on-rails-3.2ancestry

How can I find the ultimate ancestor of an ActiveRecord entry where parent_id is optional?


I have a Rails 3.2 application where Product is a model. Product contains attributes identifier, which is never null, and parent_identifier, which may be null. The relationships, when they exist, can be chained through many generations.

My challenge is to copy ProductDetail objects, a has_many of Product, over to subsequent child products.

The product details may not have been entered at the ultimate ancestor though. I only need to travel up the chain to where I encounter an ancestor product that does have product details, and then copy those under the most recent product.

How can I travel up the chain until I find these product details?

* Note: The identifier field is not the primary key, and it is not practical to make it so as the parent_identifier comes from an external database and may not even exist locally if it is from before the customer signed up. It is not practical to check for this upon each load as there are millions of products to be kept in synch daily. *


Solution

  • If I understand your challenge correctly, the following methods should provide you with what you're after (the nearest upstream non-empty ProductDetails collection).

    class Product > ActiveRecord::Base
      def parent
        @parent ||= Product.where(identifier: self.parent_identifier).first
      end
    
      def parent_product_details
        return unless parent
    
        upstream_details = parent.product_details
        upstream_details = parent.parent_product_details if upstream_details.empty?
    
        upstream_details
      end
    end
    

    Let me know if I've misunderstood the problem.