Commit c84e0cabbd250d491fba169e79b9c2e7baba3210

Authored by Rodrigo Souto
1 parent b0e5e0c9

product-category: fetch only necessary categories

Instead of fetching every category to display the icons, fetch only 3 of
them through the correct sql query. This also fixes a big memory leak.

(ActionItem3084)
app/helpers/application_helper.rb
@@ -514,24 +514,25 @@ module ApplicationHelper @@ -514,24 +514,25 @@ module ApplicationHelper
514 514
515 def profile_cat_icons( profile ) 515 def profile_cat_icons( profile )
516 if profile.class == Enterprise 516 if profile.class == Enterprise
517 - icons = profile.product_categories.map{ |c| c.size > 1 ? c[1] : nil }.  
518 - compact.uniq.map do |c|  
519 - cat_name = c.gsub( /[-_\s,.;'"]+/, '_' )  
520 - cat_icon = "/images/icons-cat/#{cat_name}.png"  
521 - if ! File.exists? RAILS_ROOT.to_s() + '/public/' + cat_icon  
522 - cat_icon = '/images/icons-cat/undefined.png'  
523 - end  
524 - content_tag('span',  
525 - content_tag( 'span', c ),  
526 - :title => c,  
527 - :class => 'product-cat-icon cat_icon_' + cat_name,  
528 - :style => "background-image:url(#{cat_icon})"  
529 - )  
530 - end.join("\n").html_safe  
531 - content_tag('div',  
532 - content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,  
533 - :class => 'product-category-icons' 517 + icons = profile.product_categories.unique_by_level(2).limit(3).map do |c|
  518 + filtered_category = c.filtered_category.blank? ? c.path.split('/').last : c.filtered_category
  519 + category_title = filtered_category.split(/[-_\s,.;'"]+/).map(&:capitalize).join(' ')
  520 + category_name = category_title.gsub(' ', '_' )
  521 + category_icon = "/images/icons-cat/#{category_name}.png"
  522 + if ! File.exists? RAILS_ROOT.to_s() + '/public/' + category_icon
  523 + category_icon = '/images/icons-cat/undefined.png'
  524 + end
  525 + content_tag('span',
  526 + content_tag( 'span', category_title ),
  527 + :title => category_title,
  528 + :class => 'product-cat-icon cat_icon_' + category_name,
  529 + :style => "background-image:url(#{category_icon})"
534 ) 530 )
  531 + end.join("\n").html_safe
  532 + content_tag('div',
  533 + content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,
  534 + :class => 'product-category-icons'
  535 + )
535 else 536 else
536 '' 537 ''
537 end 538 end
app/models/enterprise.rb
@@ -17,7 +17,7 @@ class Enterprise < Organization @@ -17,7 +17,7 @@ class Enterprise < Organization
17 has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people' 17 has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
18 18
19 def product_categories 19 def product_categories
20 - products.includes(:product_category).map{|p| p.category_full_name}.compact 20 + ProductCategory.by_enterprise(self)
21 end 21 end
22 22
23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') 23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code')
app/models/product.rb
@@ -88,10 +88,6 @@ class Product < ActiveRecord::Base @@ -88,10 +88,6 @@ class Product < ActiveRecord::Base
88 image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size 88 image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size
89 end 89 end
90 90
91 - def category_full_name  
92 - product_category ? product_category.full_name.split('/') : nil  
93 - end  
94 -  
95 acts_as_having_image 91 acts_as_having_image
96 92
97 def save_image 93 def save_image
app/models/product_category.rb
@@ -3,6 +3,15 @@ class ProductCategory < Category @@ -3,6 +3,15 @@ class ProductCategory < Category
3 has_many :products 3 has_many :products
4 has_many :inputs 4 has_many :inputs
5 5
  6 + named_scope :unique, :select => 'DISTINCT ON (path) categories.*'
  7 + named_scope :by_enterprise, lambda { |enterprise| {
  8 + :joins => :products,
  9 + :conditions => ['products.profile_id = ?', enterprise.id]
  10 + }}
  11 + named_scope :unique_by_level, lambda { |level| {
  12 + :select => "DISTINCT ON (filtered_category) split_part(path, '/', #{level}) AS filtered_category, categories.*"
  13 + }}
  14 +
6 def all_products 15 def all_products
7 Product.find(:all, :conditions => { :product_category_id => (all_children << self).map(&:id) }) 16 Product.find(:all, :conditions => { :product_category_id => (all_children << self).map(&:id) })
8 end 17 end
test/unit/enterprise_test.rb
@@ -234,12 +234,12 @@ class EnterpriseTest &lt; ActiveSupport::TestCase @@ -234,12 +234,12 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
234 assert enterprise.enable(person) 234 assert enterprise.enable(person)
235 end 235 end
236 236
237 - should 'list product categories full name' do 237 + should 'list product categories' do
238 subcategory = fast_create(ProductCategory, :name => 'Products subcategory', :parent_id => @product_category.id) 238 subcategory = fast_create(ProductCategory, :name => 'Products subcategory', :parent_id => @product_category.id)
239 ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent') 239 ent = fast_create(Enterprise, :name => 'test ent', :identifier => 'test_ent')
240 p = ent.products.create!(:name => 'test prod', :product_category => subcategory) 240 p = ent.products.create!(:name => 'test prod', :product_category => subcategory)
241 241
242 - assert_equal [p.category_full_name], ent.product_categories 242 + assert_equivalent [subcategory], ent.product_categories
243 end 243 end
244 244
245 should 'not create a products block for enterprise if environment do not let' do 245 should 'not create a products block for enterprise if environment do not let' do
test/unit/product_category_test.rb
@@ -36,4 +36,29 @@ class ProductCategoryTest &lt; ActiveSupport::TestCase @@ -36,4 +36,29 @@ class ProductCategoryTest &lt; ActiveSupport::TestCase
36 assert_equal [c11], ProductCategory.menu_categories(c1, nil) 36 assert_equal [c11], ProductCategory.menu_categories(c1, nil)
37 end 37 end
38 38
  39 + should 'provide a scope based on the enterprise' do
  40 + enterprise = fast_create(Enterprise)
  41 + c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
  42 + c2 = ProductCategory.create!(:name => 'test cat 2', :environment => Environment.default)
  43 + c3 = ProductCategory.create!(:name => 'test cat 3', :environment => Environment.default)
  44 + p1 = Product.create(:name => 'product1', :product_category => c1, :profile_id => enterprise.id)
  45 + p2 = Product.create(:name => 'product2', :product_category => c1, :profile_id => enterprise.id)
  46 + p3 = Product.create(:name => 'product3', :product_category => c2, :profile_id => enterprise.id)
  47 +
  48 + scope = ProductCategory.by_enterprise(enterprise)
  49 +
  50 + assert_equal ActiveRecord::NamedScope::Scope, scope.class
  51 + assert_equivalent [c1,c2], scope
  52 + end
  53 +
  54 + should 'fetch unique categories by level' do
  55 + c1 = ProductCategory.create!(:name => 'test cat 1', :environment => Environment.default)
  56 + c11 = ProductCategory.create!(:name => 'test cat 11', :environment => Environment.default, :parent => c1)
  57 + c12 = ProductCategory.create!(:name => 'test cat 12', :environment => Environment.default, :parent => c1)
  58 + c111 = ProductCategory.create!(:name => 'test cat 111', :environment => Environment.default, :parent => c11)
  59 + c112 = ProductCategory.create!(:name => 'test cat 112', :environment => Environment.default, :parent => c11)
  60 +
  61 + assert_equivalent ['', 'test-cat-11', 'test-cat-12'], ProductCategory.unique_by_level(2).map(&:filtered_category)
  62 + end
  63 +
39 end 64 end
test/unit/product_test.rb
@@ -89,21 +89,6 @@ class ProductTest &lt; ActiveSupport::TestCase @@ -89,21 +89,6 @@ class ProductTest &lt; ActiveSupport::TestCase
89 end 89 end
90 end 90 end
91 91
92 - should 'calculate category full name' do  
93 - cat = mock  
94 - cat.expects(:full_name).returns('A/B/C')  
95 -  
96 - p = Product.new  
97 - p.stubs(:product_category).returns(cat)  
98 - assert_equal ['A','B','C'], p.category_full_name  
99 - end  
100 -  
101 - should 'return a nil cateory full name when not categorized' do  
102 - p = Product.new  
103 - p.stubs(:product_category).returns(nil)  
104 - assert_equal nil, p.category_full_name  
105 - end  
106 -  
107 should 'have same lat and lng of its enterprise' do 92 should 'have same lat and lng of its enterprise' do
108 ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0) 93 ent = fast_create(Enterprise, :name => 'test enterprise', :identifier => 'test_enterprise', :lat => 30.0, :lng => 30.0)
109 prod = ent.products.create!(:name => 'test product', :product_category => @product_category) 94 prod = ent.products.create!(:name => 'test product', :product_category => @product_category)