diff --git a/app/models/profile.rb b/app/models/profile.rb index e966a49..05edd64 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -100,7 +100,35 @@ class Profile < ActiveRecord::Base has_many :tasks, :foreign_key => :target_id - has_and_belongs_to_many :categories + has_many :profile_categorizations, :conditions => { :virtual => false } + has_many :categories, :through => :profile_categorizations + + def pending_categorizations + @pending_categorizations ||= [] + end + + def add_category(c) + if self.id + ProfileCategorization.create!(:category => c, :profile => self) + else + pending_categorizations << c + end + end + + def category_ids=(ids) + ProfileCategorization.remove_all_for(self) + ids.each do |item| + add_category(Category.find(item)) + end + end + + after_create :create_pending_categorizations + def create_pending_categorizations + pending_categorizations.each do |item| + ProfileCategorization.create!(:category => item, :profile => self) + end + pending_categorizations.clear + end def top_level_articles(reload = false) if reload diff --git a/app/models/profile_categorization.rb b/app/models/profile_categorization.rb index 5447e60..ba33a92 100644 --- a/app/models/profile_categorization.rb +++ b/app/models/profile_categorization.rb @@ -2,4 +2,20 @@ class ProfileCategorization < ActiveRecord::Base set_table_name :categories_profiles belongs_to :profile belongs_to :category + + after_create :associate_with_entire_hierarchy + def associate_with_entire_hierarchy + return if virtual + + c = category.parent + while !c.nil? && !self.class.find(:first, :conditions => {:profile_id => profile, :category_id => c}) + self.class.create!(:profile => profile, :category => c, :virtual => true) + c = c.parent + end + end + + def self.remove_all_for(profile) + self.delete_all(:profile_id => profile.id) + end + end diff --git a/test/unit/profile_categorization_test.rb b/test/unit/profile_categorization_test.rb index 09c371c..a59baf2 100644 --- a/test/unit/profile_categorization_test.rb +++ b/test/unit/profile_categorization_test.rb @@ -12,4 +12,45 @@ class ProfileCategorizationTest < ActiveSupport::TestCase assert_equal [cat.id], person.category_ids end + should 'create instances for the entire hierarchy' do + c1 = Category.create!(:name => 'c1', :environment => Environment.default) + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default) + + p = create_user('testuser').person + + assert_difference ProfileCategorization, :count, 2 do + ProfileCategorization.create!(:category => c2, :profile => p) + end + + assert_equal 2, ProfileCategorization.find_all_by_profile_id(p.id).size + end + + should 'not duplicate entry for category that is parent of two others' do + c1 = Category.create!(:name => 'c1', :environment => Environment.default) + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default) + c3 = c1.children.create!(:name => 'c3', :environment => Environment.default) + + p = create_user('testuser').person + + assert_difference ProfileCategorization, :count, 3 do + ac = ProfileCategorization.create!(:category => c2, :profile => p) + ac = ProfileCategorization.create!(:category => c3, :profile => p) + end + end + + should 'remove all instances for a given profile' do + c1 = Category.create!(:name => 'c1', :environment => Environment.default) + c2 = c1.children.create!(:name => 'c2', :environment => Environment.default) + c3 = c1.children.create!(:name => 'c3', :environment => Environment.default) + + p = create_user('testuser').person + + ac = ProfileCategorization.create!(:category => c2, :profile => p) + ac = ProfileCategorization.create!(:category => c3, :profile => p) + + assert_difference ProfileCategorization, :count, -3 do + ProfileCategorization.remove_all_for(p) + end + end + end diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index cf631f9..1cd265e 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -540,6 +540,46 @@ class ProfileTest < Test::Unit::TestCase assert profile.enabled? end + should 'categorize in the entire category hierarchy' do + c1 = Category.create!(:environment => Environment.default, :name => 'c1') + c2 = c1.children.create!(:environment => Environment.default, :name => 'c2') + c3 = c2.children.create!(:environment => Environment.default, :name => 'c3') + + profile = create_user('testuser').person + profile.add_category(c3) + + + assert_equal [c3], profile.categories(true) + assert_equal [profile], c2.people(true) + + assert_includes c3.people(true), profile + assert_includes c2.people(true), profile + assert_includes c1.people(true), profile + end + + should 'redefine the entire category set at once' do + c1 = Category.create!(:environment => Environment.default, :name => 'c1') + c2 = c1.children.create!(:environment => Environment.default, :name => 'c2') + c3 = c2.children.create!(:environment => Environment.default, :name => 'c3') + c4 = c1.children.create!(:environment => Environment.default, :name => 'c4') + profile = Profile.create!(:name => 'my test profile', :identifier => 'mytestprofile') + + profile.add_category(c4) + + profile.category_ids = [c2,c3].map(&:id) + + assert_equivalent [c2, c3], profile.categories(true) + end + + should 'be able to create an profile already with categories' do + c1 = Category.create!(:environment => Environment.default, :name => 'c1') + c2 = Category.create!(:environment => Environment.default, :name => 'c2') + + profile = Profile.create!(:name => 'my test profile', :identifier => 'mytestprofile', :category_ids => [c1.id, c2.id]) + + assert_equivalent [c1, c2], profile.categories(true) + end + private def assert_invalid_identifier(id) -- libgit2 0.21.2