Commit ebbb202a280f1f163a6be2b117492053a6769d7b
Committed by
Daniela Feitosa
1 parent
97633c05
Exists in
master
and in
29 other branches
Using a ruby way to randomize people from ProfileListBlock
- Added 2 named scopes to select things with and without images - Priorize profiles with image by defaut in ProfileListBlock - Migration to remove unused 'image' column from products - Migration to move image references to owner of image (ActionItem1971)
Showing
11 changed files
with
143 additions
and
58 deletions
Show diff stats
app/models/image.rb
app/models/profile_list_block.rb
1 | 1 | class ProfileListBlock < Block |
2 | 2 | |
3 | 3 | settings_items :limit, :type => :integer, :default => 6 |
4 | - settings_items :prioritize_profiles_with_image, :type => :boolean, :default => false | |
4 | + settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true | |
5 | 5 | |
6 | 6 | def self.description |
7 | 7 | _('Random profiles') |
... | ... | @@ -13,21 +13,21 @@ class ProfileListBlock < Block |
13 | 13 | end |
14 | 14 | |
15 | 15 | def profile_list |
16 | - profiles.visible.all(:limit => limit, :select => 'DISTINCT profiles.*, ' + image_prioritizer + randomizer, :joins => "LEFT OUTER JOIN images ON images.owner_id = profiles.id", :order => image_prioritizer + randomizer) | |
16 | + result = nil | |
17 | + if !prioritize_profiles_with_image | |
18 | + result = profiles.visible.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand } | |
19 | + elsif profiles.visible.with_image.count >= limit | |
20 | + result = profiles.visible.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
21 | + else | |
22 | + result = profiles.visible.with_image.sort_by{ rand } + profiles.visible.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
23 | + end | |
24 | + result.slice(0..limit-1) | |
17 | 25 | end |
18 | 26 | |
19 | 27 | def profile_count |
20 | 28 | profiles.visible.count('DISTINCT(profiles.id)') |
21 | 29 | end |
22 | 30 | |
23 | - def randomizer | |
24 | - @randomizer ||= "(profiles.id % #{rand(profile_count) + 1})" | |
25 | - end | |
26 | - | |
27 | - def image_prioritizer | |
28 | - prioritize_profiles_with_image ? '(images.id is null),' : '' | |
29 | - end | |
30 | - | |
31 | 31 | # the title of the block. Probably will be overriden in subclasses. |
32 | 32 | def default_title |
33 | 33 | _('{#} People or Groups') | ... | ... |
db/migrate/20110526201202_move_reference_from_image_to_owners.rb
0 → 100644
... | ... | @@ -0,0 +1,21 @@ |
1 | +class MoveReferenceFromImageToOwners < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + %w[ profiles categories products tasks ].each do |table| | |
4 | + type = table.singularize.camelcase | |
5 | + add_column table, :image_id, :integer | |
6 | + update("update #{table} set image_id = (select i.id from images i where i.owner_id = #{table}.id and i.owner_type = '#{type}' limit 1) where id in (select owner_id from images where owner_type = '#{type}' and owner_id is not null)") | |
7 | + end | |
8 | + remove_column :images, :owner_id | |
9 | + remove_column :images, :owner_type | |
10 | + end | |
11 | + | |
12 | + def self.down | |
13 | + add_column :images, :owner_id, :integer | |
14 | + add_column :images, :owner_type, :string | |
15 | + %w[ profiles products categories tasks ].each do |table| | |
16 | + type = table.singularize.camelcase | |
17 | + update("update images set owner_id = (select id from #{table} origin where origin.image_id = images.id), owner_type = '#{type}' where id in (select image_id from #{table} where image_id is not null)") | |
18 | + remove_column table, :image_id | |
19 | + end | |
20 | + end | |
21 | +end | ... | ... |
db/migrate/20110527042608_remove_unused_column_from_products.rb
0 → 100644
db/schema.rb
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | # |
10 | 10 | # It's strongly recommended to check this file into your version control system. |
11 | 11 | |
12 | -ActiveRecord::Schema.define(:version => 20110524151137) do | |
12 | +ActiveRecord::Schema.define(:version => 20110527042608) do | |
13 | 13 | |
14 | 14 | create_table "action_tracker", :force => true do |t| |
15 | 15 | t.integer "user_id" |
... | ... | @@ -165,6 +165,7 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
165 | 165 | t.boolean "display_in_menu", :default => false |
166 | 166 | t.integer "children_count", :default => 0 |
167 | 167 | t.boolean "accept_products", :default => true |
168 | + t.integer "image_id" | |
168 | 169 | end |
169 | 170 | |
170 | 171 | create_table "categories_profiles", :id => false, :force => true do |t| |
... | ... | @@ -270,8 +271,6 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
270 | 271 | end |
271 | 272 | |
272 | 273 | create_table "images", :force => true do |t| |
273 | - t.string "owner_type" | |
274 | - t.integer "owner_id" | |
275 | 274 | t.integer "parent_id" |
276 | 275 | t.string "content_type" |
277 | 276 | t.string "filename" |
... | ... | @@ -339,7 +338,6 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
339 | 338 | t.string "name" |
340 | 339 | t.decimal "price" |
341 | 340 | t.text "description" |
342 | - t.string "image" | |
343 | 341 | t.datetime "created_at" |
344 | 342 | t.datetime "updated_at" |
345 | 343 | t.float "lat" |
... | ... | @@ -348,6 +346,7 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
348 | 346 | t.boolean "available", :default => true |
349 | 347 | t.boolean "highlighted" |
350 | 348 | t.integer "unit_id" |
349 | + t.integer "image_id" | |
351 | 350 | end |
352 | 351 | |
353 | 352 | add_index "products", ["enterprise_id"], :name => "index_products_on_enterprise_id" |
... | ... | @@ -378,6 +377,7 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
378 | 377 | t.integer "preferred_domain_id" |
379 | 378 | t.datetime "updated_at" |
380 | 379 | t.boolean "visible", :default => true |
380 | + t.integer "image_id" | |
381 | 381 | end |
382 | 382 | |
383 | 383 | add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id" |
... | ... | @@ -456,6 +456,7 @@ ActiveRecord::Schema.define(:version => 20110524151137) do |
456 | 456 | t.string "type" |
457 | 457 | t.datetime "created_at" |
458 | 458 | t.string "target_type" |
459 | + t.integer "image_id" | |
459 | 460 | end |
460 | 461 | |
461 | 462 | create_table "thumbnails", :force => true do |t| | ... | ... |
features/step_definitions/noosfero_steps.rb
... | ... | @@ -116,8 +116,8 @@ Given /^the following products?$/ do |table| |
116 | 116 | data = item.dup |
117 | 117 | owner = Enterprise[data.delete("owner")] |
118 | 118 | category = Category.find_by_slug(data.delete("category").to_slug) |
119 | - product = Product.create!(data.merge(:enterprise => owner, :product_category => category)) | |
120 | - image = Image.create!(:owner => product, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
119 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
120 | + product = Product.create!(data.merge(:enterprise => owner, :product_category => category, :image_id => img.id)) | |
121 | 121 | end |
122 | 122 | end |
123 | 123 | ... | ... |
lib/acts_as_having_image.rb
... | ... | @@ -2,7 +2,9 @@ module ActsAsHavingImage |
2 | 2 | |
3 | 3 | module ClassMethods |
4 | 4 | def acts_as_having_image |
5 | - has_one :image, :as => 'owner' | |
5 | + belongs_to :image | |
6 | + named_scope :with_image, :conditions => [ "#{table_name}.image_id IS NOT NULL" ] | |
7 | + named_scope :without_image, :conditions => [ "#{table_name}.image_id IS NULL" ] | |
6 | 8 | self.send(:include, ActsAsHavingImage) |
7 | 9 | end |
8 | 10 | end | ... | ... |
test/factories.rb
test/unit/image_test.rb
... | ... | @@ -22,7 +22,8 @@ class ImageTest < Test::Unit::TestCase |
22 | 22 | end |
23 | 23 | |
24 | 24 | should 'create thumbnails after processing jobs' do |
25 | - file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => profile) | |
25 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
26 | + profile.update_attribute(:image_id, file.id) | |
26 | 27 | |
27 | 28 | process_delayed_job_queue |
28 | 29 | Image.attachment_options[:thumbnails].each do |suffix, size| |
... | ... | @@ -32,7 +33,8 @@ class ImageTest < Test::Unit::TestCase |
32 | 33 | end |
33 | 34 | |
34 | 35 | should 'set thumbnails_processed to true after creating thumbnails' do |
35 | - file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => profile) | |
36 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
37 | + profile.update_attribute(:image_id, file.id) | |
36 | 38 | |
37 | 39 | process_delayed_job_queue |
38 | 40 | |
... | ... | @@ -62,7 +64,8 @@ class ImageTest < Test::Unit::TestCase |
62 | 64 | end |
63 | 65 | |
64 | 66 | should 'return image thumbnail if thumbnails were processed' do |
65 | - file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => profile) | |
67 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
68 | + profile.update_attribute(:image_id, file.id) | |
66 | 69 | process_delayed_job_queue |
67 | 70 | |
68 | 71 | assert_match(/rails_thumb.png/, Image.find(file.id).public_filename(:thumb)) |
... | ... | @@ -71,7 +74,8 @@ class ImageTest < Test::Unit::TestCase |
71 | 74 | end |
72 | 75 | |
73 | 76 | should 'store width and height after processing' do |
74 | - file = Image.create!(:owner => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
77 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
78 | + profile.update_attribute(:image_id, file.id) | |
75 | 79 | file.create_thumbnails |
76 | 80 | |
77 | 81 | file = Image.find(file.id) |
... | ... | @@ -89,7 +93,7 @@ class ImageTest < Test::Unit::TestCase |
89 | 93 | # this test verifies whether it created background jobs also for the |
90 | 94 | # thumbnails! |
91 | 95 | assert_no_difference Delayed::Job, :count do |
92 | - image = Image.new(:owner => profile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
96 | + image = Image.new(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
93 | 97 | image.stubs(:is_thumbnail?).returns(true) |
94 | 98 | image.save! |
95 | 99 | end |
... | ... | @@ -97,7 +101,8 @@ class ImageTest < Test::Unit::TestCase |
97 | 101 | |
98 | 102 | should 'upload to a folder with same name as the schema if database is postgresql' do |
99 | 103 | uses_postgresql |
100 | - file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => profile) | |
104 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
105 | + profile.update_attribute(:image_id, file.id) | |
101 | 106 | process_delayed_job_queue |
102 | 107 | assert_match(/images\/test_schema\/\d{4}\/\d{4}\/rails.png/, Image.find(file.id).public_filename) |
103 | 108 | file.destroy |
... | ... | @@ -106,7 +111,8 @@ class ImageTest < Test::Unit::TestCase |
106 | 111 | |
107 | 112 | should 'upload to path prefix folder if database is not postgresql' do |
108 | 113 | uses_sqlite |
109 | - file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => profile) | |
114 | + file = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
115 | + profile.update_attribute(:image_id, file.id) | |
110 | 116 | process_delayed_job_queue |
111 | 117 | assert_match(/images\/\d{4}\/\d{4}\/rails.png/, Image.find(file.id).public_filename) |
112 | 118 | file.destroy | ... | ... |
test/unit/profile_list_block_test.rb
... | ... | @@ -137,50 +137,80 @@ class ProfileListBlockTest < Test::Unit::TestCase |
137 | 137 | |
138 | 138 | should 'list random profiles' do |
139 | 139 | env = fast_create(Environment) |
140 | - p1 = fast_create(Person, :environment_id => env.id) | |
141 | - p2 = fast_create(Person, :environment_id => env.id) | |
142 | - p3 = fast_create(Person, :environment_id => env.id) | |
140 | + 6.times.each do | |
141 | + fast_create(Person, :environment_id => env.id) | |
142 | + end | |
143 | 143 | |
144 | 144 | block = ProfileListBlock.new |
145 | 145 | block.stubs(:owner).returns(env) |
146 | 146 | |
147 | - # force the "random" function to return something we know | |
148 | - block.stubs(:randomizer).returns('-profiles.id') | |
149 | - | |
150 | - assert_equal [p3.id, p2.id, p1.id], block.profile_list.map(&:id) | |
147 | + assert_not_equal block.profile_list.map(&:id), block.profile_list.map(&:id) | |
151 | 148 | end |
152 | 149 | |
153 | - should 'randomize using modulo operator and random number' do | |
154 | - block = ProfileListBlock.new | |
155 | - block.expects(:profile_count).returns(10) | |
156 | - block.expects(:rand).with(10).returns(5) | |
157 | - assert_match /profiles.id % 6/, block.randomizer | |
150 | + should 'prioritize profiles with image if this option is turned on' do | |
151 | + env = fast_create(Environment) | |
152 | + img1 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
153 | + p1 = fast_create(Person, :environment_id => env.id, :image_id => img1.id) | |
154 | + img2 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
155 | + p2 = fast_create(Person, :environment_id => env.id, :image_id => img2.id) | |
156 | + | |
157 | + p_without_image = fast_create(Person, :environment_id => env.id) | |
158 | + | |
159 | + block = ProfileListBlock.new(:limit => 2) | |
160 | + block.stubs(:owner).returns(env) | |
161 | + block.stubs(:prioritize_profiles_with_image).returns(true) | |
162 | + | |
163 | + assert_not_includes block.profile_list[0..1], p_without_image | |
158 | 164 | end |
159 | 165 | |
160 | - should 'not divide by zero' do | |
166 | + should 'list profiles without image only if profiles with image arent enought' do | |
167 | + env = fast_create(Environment) | |
168 | + img1 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
169 | + p1 = fast_create(Person, :environment_id => env.id, :image_id => img1.id) | |
170 | + img2 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
171 | + p2 = fast_create(Person, :environment_id => env.id, :image_id => img2.id) | |
172 | + p_without_image = fast_create(Person, :environment_id => env.id) | |
161 | 173 | block = ProfileListBlock.new |
162 | - block.stubs(:profile_count).returns(0) | |
163 | - block.expects(:rand).returns(0) | |
164 | - assert_no_match /profiles.id % 0/, block.randomizer | |
174 | + block.stubs(:owner).returns(env) | |
175 | + block.stubs(:prioritize_profiles_with_image).returns(true) | |
176 | + | |
177 | + block.limit = 2 | |
178 | + assert_not_includes block.profile_list, p_without_image | |
179 | + | |
180 | + block.limit = 3 | |
181 | + assert_includes block.profile_list, p_without_image | |
165 | 182 | end |
166 | 183 | |
167 | - should 'prioritize profiles with image if this option is turned on' do | |
184 | + should 'list profile with image among profiles without image' do | |
168 | 185 | env = fast_create(Environment) |
169 | - p1 = fast_create(Person, :environment_id => env.id) | |
170 | - img1 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => p1) | |
171 | - p2 = fast_create(Person, :environment_id => env.id) | |
172 | - img2 = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :owner => p2) | |
186 | + 5.times do |n| | |
187 | + fast_create(Person, :environment_id => env.id) | |
188 | + end | |
189 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
190 | + with_image = fast_create(Person, :environment_id => env.id, :image_id => img.id) | |
191 | + block = ProfileListBlock.new(:limit => 3) | |
192 | + block.stubs(:prioritize_profiles_with_image).returns(true) | |
193 | + block.stubs(:owner).returns(env) | |
194 | + assert_includes block.profile_list, with_image | |
195 | + end | |
173 | 196 | |
174 | - p_without_image = fast_create(Person, :environment_id => env.id) | |
197 | + should 'not prioritize profiles with image if this option is turned off' do | |
198 | + env = fast_create(Environment) | |
199 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
200 | + with_image = fast_create(Person, :environment_id => env.id, :updated_at => DateTime.now, :image_id => img.id) | |
201 | + 5.times do |n| | |
202 | + fast_create(Person, :environment_id => env.id, :updated_at => DateTime.now + 1.day) | |
203 | + end | |
175 | 204 | |
176 | - block = ProfileListBlock.new | |
205 | + block = ProfileListBlock.new(:limit => 3) | |
177 | 206 | block.stubs(:owner).returns(env) |
178 | - block.stubs(:prioritize_profiles_with_image).returns(true) | |
207 | + block.stubs(:prioritize_profiles_with_image).returns(false) | |
179 | 208 | |
180 | - # force the "random" function to return something we know | |
181 | - block.stubs(:randomizer).returns('-profiles.id') | |
209 | + assert_not_includes block.profile_list, with_image | |
210 | + end | |
182 | 211 | |
183 | - assert_not_includes block.profile_list[0..1], p_without_image | |
212 | + should 'prioritize profiles with image by default' do | |
213 | + assert ProfileListBlock.new.prioritize_profiles_with_image | |
184 | 214 | end |
185 | 215 | |
186 | 216 | end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -1357,12 +1357,6 @@ class ProfileTest < Test::Unit::TestCase |
1357 | 1357 | assert !profile.folders.include?(child) |
1358 | 1358 | end |
1359 | 1359 | |
1360 | - should 'validates profile image when save' do | |
1361 | - profile = build(Profile, :image_builder => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')}) | |
1362 | - profile.image.expects(:valid?).returns(false).at_least_once | |
1363 | - assert !profile.valid? | |
1364 | - end | |
1365 | - | |
1366 | 1360 | should 'profile is invalid when image not valid' do |
1367 | 1361 | profile = build(Profile, :image_builder => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')}) |
1368 | 1362 | profile.image.expects(:valid?).returns(false).at_least_once |
... | ... | @@ -1710,6 +1704,28 @@ class ProfileTest < Test::Unit::TestCase |
1710 | 1704 | assert profile.is_on_homepage?("/#{profile.identifier}/#{homepage.slug}", homepage) |
1711 | 1705 | end |
1712 | 1706 | |
1707 | + should 'find profiles with image' do | |
1708 | + env = fast_create(Environment) | |
1709 | + 2.times do |n| | |
1710 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
1711 | + fast_create(Person, :name => "with_image_#{n}", :environment_id => env.id, :image_id => img.id) | |
1712 | + end | |
1713 | + without_image = fast_create(Person, :name => 'without_image', :environment_id => env.id) | |
1714 | + assert_equal 2, env.profiles.with_image.count | |
1715 | + assert_not_includes env.profiles.with_image, without_image | |
1716 | + end | |
1717 | + | |
1718 | + should 'find profiles withouth image' do | |
1719 | + env = fast_create(Environment) | |
1720 | + 2.times do |n| | |
1721 | + fast_create(Person, :name => "without_image_#{n}", :environment_id => env.id) | |
1722 | + end | |
1723 | + img = Image.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')) | |
1724 | + with_image = fast_create(Person, :name => 'with_image', :environment_id => env.id, :image_id => img.id) | |
1725 | + assert_equal 2, env.profiles.without_image.count | |
1726 | + assert_not_includes env.profiles.without_image, with_image | |
1727 | + end | |
1728 | + | |
1713 | 1729 | private |
1714 | 1730 | |
1715 | 1731 | def assert_invalid_identifier(id) | ... | ... |