Commit 5451b3b986d042c303e35db730682cbfcf09ab18

Authored by AntonioTerceiro
1 parent 590bfeff

ActionItem466: changing article categorization

we'll categorize articles in every category from the actual category
chosen by the user to the root of its hierarchy.


git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@2068 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/models/article.rb
... ... @@ -12,7 +12,35 @@ class Article < ActiveRecord::Base
12 12  
13 13 has_many :comments, :dependent => :destroy
14 14  
15   - has_and_belongs_to_many :categories
  15 + has_many :article_categorizations, :conditions => { :virtual => false }
  16 + has_many :categories, :through => :article_categorizations
  17 +
  18 + def pending_categorizations
  19 + @pending_categorizations ||= []
  20 + end
  21 +
  22 + def add_category(c)
  23 + if self.id
  24 + ArticleCategorization.create!(:category => c, :article => self)
  25 + else
  26 + pending_categorizations << c
  27 + end
  28 + end
  29 +
  30 + def category_ids=(ids)
  31 + ArticleCategorization.remove_all_for(self)
  32 + ids.each do |item|
  33 + add_category(Category.find(item))
  34 + end
  35 + end
  36 +
  37 + after_create :create_pending_categorizations
  38 + def create_pending_categorizations
  39 + pending_categorizations.each do |item|
  40 + ArticleCategorization.create!(:category => item, :article => self)
  41 + end
  42 + pending_categorizations.clear
  43 + end
16 44  
17 45 acts_as_taggable
18 46 N_('Tag list')
... ...
app/models/article_categorization.rb
... ... @@ -2,4 +2,20 @@ class ArticleCategorization &lt; ActiveRecord::Base
2 2 set_table_name :articles_categories
3 3 belongs_to :article
4 4 belongs_to :category
  5 +
  6 + after_create :associate_with_entire_hierarchy
  7 + def associate_with_entire_hierarchy
  8 + return if virtual
  9 +
  10 + c = category.parent
  11 + while !c.nil? && !self.class.find(:first, :conditions => {:article_id => article, :category_id => c})
  12 + self.class.create!(:article => article, :category => c, :virtual => true)
  13 + c = c.parent
  14 + end
  15 + end
  16 +
  17 + def self.remove_all_for(article)
  18 + self.delete_all(:article_id => article.id)
  19 + end
  20 +
5 21 end
... ...
db/migrate/043_add_virtual_flag_to_categorizations.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class AddVirtualFlagToCategorizations < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :articles_categories, :virtual, :boolean, :default => false
  4 + add_column :categories_profiles, :virtual, :boolean, :default => false
  5 + end
  6 +
  7 + def self.down
  8 + remove_column :articles_categories, :virtual
  9 + remove_column :categories_profiles, :virtual
  10 + end
  11 +end
... ...
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 => 42) do
  12 +ActiveRecord::Schema.define(:version => 43) do
13 13  
14 14 create_table "article_versions", :force => true do |t|
15 15 t.integer "article_id"
... ... @@ -68,6 +68,7 @@ ActiveRecord::Schema.define(:version =&gt; 42) do
68 68 create_table "articles_categories", :id => false, :force => true do |t|
69 69 t.integer "article_id"
70 70 t.integer "category_id"
  71 + t.boolean "virtual", :default => false
71 72 end
72 73  
73 74 add_index "articles_categories", ["category_id"], :name => "index_articles_categories_on_category_id"
... ... @@ -104,6 +105,7 @@ ActiveRecord::Schema.define(:version =&gt; 42) do
104 105 create_table "categories_profiles", :id => false, :force => true do |t|
105 106 t.integer "profile_id"
106 107 t.integer "category_id"
  108 + t.boolean "virtual", :default => false
107 109 end
108 110  
109 111 create_table "comments", :force => true do |t|
... ...
test/functional/cms_controller_test.rb
... ... @@ -281,7 +281,7 @@ class CmsControllerTest &lt; Test::Unit::TestCase
281 281 # post is in c1 and c3
282 282 post :new, :type => TextileArticle.name, :profile => profile.identifier, :article => { :name => 'adding-categories-test', :category_ids => [ c1.id, c3.id] }
283 283  
284   - saved = TextileArticle.find_by_name('adding-categories-test')
  284 + saved = profile.articles.find_by_name('adding-categories-test')
285 285 assert_includes saved.categories, c1
286 286 assert_not_includes saved.categories, c2
287 287 assert_includes saved.categories, c3
... ...
test/unit/article_categorization_test.rb
... ... @@ -17,4 +17,48 @@ class ArticleCategorizationTest &lt; Test::Unit::TestCase
17 17 assert_equal category, ArticleCategorization.new(:category => category).category
18 18 end
19 19  
  20 + should 'create instances for the entire hierarchy' do
  21 + c1 = Category.create!(:name => 'c1', :environment => Environment.default)
  22 + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default)
  23 +
  24 + p = create_user('testuser').person
  25 + a = p.articles.create!(:name => 'test')
  26 +
  27 + assert_difference ArticleCategorization, :count, 2 do
  28 + ArticleCategorization.create!(:category => c2, :article => a)
  29 + end
  30 +
  31 + assert_equal 2, ArticleCategorization.find_all_by_article_id(a.id).size
  32 + end
  33 +
  34 + should 'not duplicate entry for category that is parent of two others' do
  35 + c1 = Category.create!(:name => 'c1', :environment => Environment.default)
  36 + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default)
  37 + c3 = c1.children.create!(:name => 'c3', :environment => Environment.default)
  38 +
  39 + p = create_user('testuser').person
  40 + a = p.articles.create!(:name => 'test')
  41 +
  42 + assert_difference ArticleCategorization, :count, 3 do
  43 + ac = ArticleCategorization.create!(:category => c2, :article => a)
  44 + ac = ArticleCategorization.create!(:category => c3, :article => a)
  45 + end
  46 + end
  47 +
  48 + should 'remove all instances for a given article' do
  49 + c1 = Category.create!(:name => 'c1', :environment => Environment.default)
  50 + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default)
  51 + c3 = c1.children.create!(:name => 'c3', :environment => Environment.default)
  52 +
  53 + p = create_user('testuser').person
  54 + a = p.articles.create!(:name => 'test')
  55 +
  56 + ac = ArticleCategorization.create!(:category => c2, :article => a)
  57 + ac = ArticleCategorization.create!(:category => c3, :article => a)
  58 +
  59 + assert_difference ArticleCategorization, :count, -3 do
  60 + ArticleCategorization.remove_all_for(a)
  61 + end
  62 + end
  63 +
20 64 end
... ...
test/unit/article_test.rb
... ... @@ -183,6 +183,8 @@ class ArticleTest &lt; Test::Unit::TestCase
183 183 article.categories << c1
184 184 article.categories << c2
185 185 end
  186 +
  187 + assert_equivalent [c1,c2], article.categories(true)
186 188 end
187 189  
188 190 should 'remove comments when removing article' do
... ... @@ -324,4 +326,48 @@ class ArticleTest &lt; Test::Unit::TestCase
324 326  
325 327 end
326 328  
  329 + should 'categorize in the entire category hierarchy' do
  330 + c1 = Category.create!(:environment => Environment.default, :name => 'c1')
  331 + c2 = c1.children.create!(:environment => Environment.default, :name => 'c2')
  332 + c3 = c2.children.create!(:environment => Environment.default, :name => 'c3')
  333 +
  334 + owner = create_user('testuser').person
  335 + art = owner.articles.create!(:name => 'ytest')
  336 +
  337 + art.add_category(c3)
  338 +
  339 + assert_equal [c3], art.categories(true)
  340 + assert_equal [art], c2.articles(true)
  341 +
  342 + assert_includes c3.articles(true), art
  343 + assert_includes c2.articles(true), art
  344 + assert_includes c1.articles(true), art
  345 + end
  346 +
  347 + should 'redefine the entire category set at once' do
  348 + c1 = Category.create!(:environment => Environment.default, :name => 'c1')
  349 + c2 = c1.children.create!(:environment => Environment.default, :name => 'c2')
  350 + c3 = c2.children.create!(:environment => Environment.default, :name => 'c3')
  351 + c4 = c1.children.create!(:environment => Environment.default, :name => 'c4')
  352 + owner = create_user('testuser').person
  353 + art = owner.articles.create!(:name => 'ytest')
  354 +
  355 + art.add_category(c4)
  356 +
  357 + art.category_ids = [c2,c3].map(&:id)
  358 +
  359 + assert_equivalent [c2, c3], art.categories(true)
  360 + end
  361 +
  362 + should 'be able to create an article already with categories' do
  363 + c1 = Category.create!(:environment => Environment.default, :name => 'c1')
  364 + c2 = Category.create!(:environment => Environment.default, :name => 'c2')
  365 +
  366 + p = create_user('testinguser').person
  367 + a = p.articles.create!(:name => 'test', :category_ids => [c1.id, c2.id])
  368 +
  369 + assert_equivalent [c1, c2], a.categories(true)
  370 +
  371 + end
  372 +
327 373 end
... ...