1

I am trying to roll out my own e-commerce solution. Extending the depot application explained in the Pragmatic Web Development with Rails book.

I am currently trying to figure out attachments. Essentially I want Product and Product_Variants to use Product_Shots for attached photos. This could result in the product_shots table with empty values for product_variants, because not all products have prodcut_variants. Is there a better approach to implement this?

Product model:

 class Product < ActiveRecord::Base

 validates :title, :description, :price, :presence=>true
 validates :title, :uniqueness => true
 validates :price, :numericality =>{:greater_than_or_equal_to => 0.01}



 has_many :line_items
 before_destroy :ensure_not_referenced_by_any_line_item

 has_and_belongs_to_many :product_categories
 has_many :product_variants

 has_many :product_shots, :dependent => :destroy
 accepts_nested_attributes_for :product_shots, :allow_destroy => true,
                            :reject_if => proc { |attributes| attributes['shot'].blank?

 }

private
def ensure_not_referenced_by_any_line_item
  if line_items.empty?
    return true
  else
  errors.add(:base, "Line items present")
end

end
end

Product Variant model

class ProductVariant < ActiveRecord::Base

  belongs_to :product
  belongs_to :product_categories

  has_many :variant_attributes
  has_many :product_shots # can I do this?
end

Product Shots model (handled by Paperclip)

class ProductShot < ActiveRecord::Base
  belongs_to :product, :dependent =>:destroy
  #Can I do this?
  belongs_to :product_variant, :dependent => :destroy

  has_attached_file :shot, :styles => { :medium => "637x471>", 
                :thumb => Proc.new { |instance| instance.resize }},
                :url => "/shots/:style/:basename.:extension",
                :path =>":rails_root/public/shots/:style/:basename.:extension"


  validates_attachment_content_type :shot, :content_type => ['image/png', 'image/jpg', 'image/jpeg', 'image/gif  ']                  
  validates_attachment_size :shot, :less_than => 2.megabytes


 ### End Paperclip ####

 def resize     
     geo = Paperclip::Geometry.from_file(shot.to_file(:original))

     ratio = geo.width/geo.height  

     min_width  = 142
     min_height = 119

      if ratio > 1
        # Horizontal Image
        final_height = min_height
        final_width  = final_height * ratio
        "#{final_width.round}x#{final_height.round}!"
      else
       # Vertical Image
       final_width  = min_width
       final_height = final_width * ratio
       "#{final_height.round}x#{final_width.round}!"
     end
   end 
end
shingara
  • 46,608
  • 11
  • 99
  • 105
frishi
  • 862
  • 1
  • 10
  • 27

1 Answers1

2

If I were to implement this, I think I would do it as a polymorphic relationship. So in product.rb and product_variant.rb:

has_many :product_shots, :dependent => :destroy, :as => :pictureable

And in product_shot.rb:

belongs_to :pictureable, :polymorphic => true

Now either product and product_variant can have as many (or as few) product_shots as they want, and both are accessible as product.product_shots and product_variant.product_shots. Just make sure you set up your database correctly -- your product_shots table will need pictureable_type and pictureable_id for this to work.

Veraticus
  • 15,944
  • 3
  • 41
  • 45