Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 4325

Show
Ignore:
Timestamp:
05/06/06 23:37:56 (2 years ago)
Author:
bitsweat
Message:

Allow :uniq => true with has_many :through associations.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r4315 r4325  
    11*SVN* 
     2 
     3* Allow :uniq => true with has_many :through associations. [Jeremy Kemper] 
    24 
    35* Ensure that StringIO is always available for the Schema dumper. [Marcel Molina Jr.] 
  • trunk/activerecord/lib/active_record/associations.rb

    r4310 r4325  
    520520      #   inferred from the association.  <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or 
    521521      #   +:subscriber+ on +Subscription+, unless a +:source+ is given. 
     522      # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through. 
    522523      # 
    523524      # Option examples: 
     
    10491050            :select, :conditions, :include, :order, :group, :limit, :offset, 
    10501051            :as, :through, :source, 
     1052            :uniq, 
    10511053            :finder_sql, :counter_sql,  
    10521054            :before_add, :after_add, :before_remove, :after_remove,  
     
    10861088            :class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,  
    10871089            :select, :conditions, :include, :order, :group, :limit, :offset, 
    1088             :finder_sql, :delete_sql, :insert_sql, :uniq,  
     1090            :uniq,  
     1091            :finder_sql, :delete_sql, :insert_sql, 
    10891092            :before_add, :after_add, :before_remove, :after_remove,  
    10901093            :extend 
  • trunk/activerecord/lib/active_record/associations/association_collection.rb

    r4144 r4325  
    1010   
    1111      def reset 
    12         @target = [] 
     12        reset_target! 
    1313        @loaded = false 
    1414      end 
     
    2929          end 
    3030        end 
    31                                  
     31 
    3232        result && self 
    3333      end 
     
    4040        load_target 
    4141        delete(@target) 
    42         @target = [] 
     42        reset_target! 
    4343      end 
    4444 
     
    7878        end 
    7979 
    80         @target = [] 
     80        reset_target! 
    8181      end 
    82        
     82 
    8383      def create(attributes = {}) 
    8484        # Can't use Base.create since the foreign key may be a protected attribute. 
     
    9696      # and you need to fetch that collection afterwards, it'll take one less SELECT query if you use length. 
    9797      def size 
    98         if loaded? then @target.size else count_records end 
     98        if loaded? && !@reflection.options[:uniq] then @target.size else count_records end 
    9999      end 
    100        
     100 
    101101      # Returns the size of the collection by loading it and calling size on the array. If you want to use this method to check 
    102102      # whether the collection is empty, use collection.length.zero? instead of collection.empty? 
     
    104104        load_target.size 
    105105      end 
    106        
     106 
    107107      def empty? 
    108108        size.zero? 
    109109      end 
    110        
     110 
    111111      def uniq(collection = self) 
    112         collection.inject([]) { |uniq_records, record| uniq_records << record unless uniq_records.include?(record); uniq_records } 
     112        collection.to_set.to_a 
    113113      end 
    114114 
     
    127127        end 
    128128      end 
     129 
     130      protected 
     131        def reset_target! 
     132          @target = Array.new 
     133        end 
     134 
     135        def find_target 
     136          records = 
     137            if @reflection.options[:finder_sql] 
     138              @reflection.klass.find_by_sql(@finder_sql) 
     139            else 
     140              find(:all) 
     141            end 
     142 
     143          @reflection.options[:uniq] ? uniq(records) : records 
     144        end 
    129145 
    130146      private 
  • trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb

    r4123 r4325  
    6969        self 
    7070      end 
    71        
     71 
    7272      alias :concat_with_attributes :push_with_attributes 
    7373 
    74       def size 
    75         @reflection.options[:uniq] ? count_records : super 
    76       end 
    77        
    7874      protected 
    7975        def method_missing(method, *args, &block) 
     
    8682          end 
    8783        end 
    88              
    89         def find_target 
    90           if @reflection.options[:finder_sql] 
    91             records = @reflection.klass.find_by_sql(@finder_sql) 
    92           else 
    93             records = find(:all) 
    94           end 
    95            
    96           @reflection.options[:uniq] ? uniq(records) : records 
    97         end 
    98          
     84 
    9985        def count_records 
    10086          load_target.size 
  • trunk/activerecord/lib/active_record/associations/has_many_association.rb

    r4237 r4325  
    107107          end 
    108108        end 
    109              
    110         def find_target 
    111           if @reflection.options[:finder_sql] 
    112             @reflection.klass.find_by_sql(@finder_sql) 
    113           else 
    114             find(:all) 
    115           end 
    116         end 
    117109 
    118110        def count_records 
  • trunk/activerecord/lib/active_record/associations/has_many_through_association.rb

    r4265 r4325  
    5757          end 
    5858        end 
    59              
     59 
    6060        def find_target 
    61           @reflection.klass.find(:all,  
     61          records = @reflection.klass.find(:all,  
    6262            :select     => construct_select, 
    6363            :conditions => construct_conditions, 
     
    6969            :include    => @reflection.options[:include] || @reflection.source_reflection.options[:include] 
    7070          ) 
     71 
     72          @reflection.options[:uniq] ? records.to_set.to_a : records 
    7173        end 
    7274 
  • trunk/activerecord/test/associations_cascaded_eager_loading_test.rb

    r4022 r4325  
    2929    assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i} 
    3030    assert_equal 1, authors[0].categorizations.size 
    31     assert_equal 1, authors[1].categorizations.size 
     31    assert_equal 2, authors[1].categorizations.size 
    3232  end 
    3333 
  • trunk/activerecord/test/associations_join_model_test.rb

    r4265 r4325  
    1313 
    1414  def test_has_many 
    15     assert_equal categories(:general), authors(:david).categories.first 
    16   end 
    17    
     15    assert authors(:david).categories.include?(categories(:general)) 
     16  end 
     17 
    1818  def test_has_many_inherited 
    19     assert_equal categories(:sti_test), authors(:mary).categories.first 
     19    assert authors(:mary).categories.include?(categories(:sti_test)) 
    2020  end 
    2121 
    2222  def test_inherited_has_many 
    23     assert_equal authors(:mary), categories(:sti_test).authors.first 
    24   end 
    25    
     23    assert categories(:sti_test).authors.include?(authors(:mary)) 
     24  end 
     25 
     26  def test_has_many_uniq_through_join_model 
     27    assert_equal 2, authors(:mary).categorized_posts.size 
     28    assert_equal 1, authors(:mary).unique_categorized_posts.size 
     29  end 
     30 
    2631  def test_polymorphic_has_many 
    27     assert_equal taggings(:welcome_general), posts(:welcome).taggings.first 
    28   end 
    29    
     32    assert posts(:welcome).taggings.include?(taggings(:welcome_general)) 
     33  end 
     34 
    3035  def test_polymorphic_has_one 
    3136    assert_equal taggings(:welcome_general), posts(:welcome).tagging 
  • trunk/activerecord/test/fixtures/author.rb

    r4169 r4325  
    2626  has_many :categorizations 
    2727  has_many :categories, :through => :categorizations 
     28 
     29  has_many :categorized_posts, :through => :categorizations, :source => :post 
     30  has_many :unique_categorized_posts, :through => :categorizations, :source => :post, :uniq => true 
    2831 
    2932  has_many :nothings, :through => :kateggorisatons, :class_name => 'Category' 
  • trunk/activerecord/test/fixtures/categorizations.yml

    r3315 r4325  
    44  post_id: 1 
    55  category_id: 1 
    6    
     6 
    77mary_thinking_sti: 
    88  id: 2 
     
    1010  post_id: 2 
    1111  category_id: 3 
     12 
     13mary_thinking_general: 
     14  id: 3 
     15  author_id: 2 
     16  post_id: 2 
     17  category_id: 1