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

Changeset 4123

Show
Ignore:
Timestamp:
04/01/06 20:03:10 (3 years ago)
Author:
david
Message:

Fixed that records returned from has_and_belongs_to_many associations with additional attributes should be marked as read only (fixes #4512) [DHH] DEPRECATED: Using additional attributes on has_and_belongs_to_many associations. Instead upgrade your association to be a real join model [DHH]

Files:

Legend:

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

    r4107 r4123  
    11*SVN* 
     2 
     3* DEPRECATED: Using additional attributes on has_and_belongs_to_many associations. Instead upgrade your association to be a real join model [DHH] 
     4 
     5* Fixed that records returned from has_and_belongs_to_many associations with additional attributes should be marked as read only (fixes #4512) [DHH] 
    26 
    37* Do not implicitly mark recordss of has_many :through as readonly but do mark habtm records as readonly (eventually only on join tables without rich attributes). [Marcel Mollina Jr.] 
  • trunk/activerecord/lib/active_record/associations.rb

    r4084 r4123  
    699699      # will give the default join table name of "developers_projects" because "D" outranks "P". 
    700700      # 
    701       # Any additional fields added to the join table will be placed as attributes when pulling records out through 
    702       # has_and_belongs_to_many associations. This is helpful when have information about the association itself 
    703       # that you want available on retrieval. Note that any fields in the join table will override matching field names 
    704       # in the two joined tables. As a consequence, having an "id" field in the join table usually has the undesirable 
    705       # result of clobbering the "id" fields in either of the other two tables. 
     701      # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through 
     702      # has_and_belongs_to_many associations. Records returned from join tables with additional attributes will be marked as 
     703      # ReadOnly (because we can't save changes to the additional attrbutes). It's strongly recommended that you upgrade any 
     704      # associations with attributes to a real join model (see introduction). 
    706705      # 
    707706      # Adds the following methods for retrieval and query. 
     
    715714      #   also holds the attributes from <tt>join_attributes</tt> (should be a hash with the column names as keys). This can be used to have additional 
    716715      #   attributes on the join, which will be injected into the associated objects when they are retrieved through the collection. 
    717       #   (collection.concat_with_attributes is an alias to this method). 
     716      #   (collection.concat_with_attributes is an alias to this method). This method is now deprecated. 
    718717      # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table.   
    719718      #   This does not destroy the objects. 
  • trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb

    r4107 r4123  
    4141 
    4242          options[:conditions] = conditions 
    43           options[:joins] = @join_sql 
    44           options[:readonly] ||= !options[:joins].nil? 
     43          options[:joins]      = @join_sql 
     44          options[:readonly]   = finding_with_ambigious_select?(options[:select]) 
    4545 
    4646          if options[:order] && @reflection.options[:order] 
     
    158158          @join_sql = "INNER JOIN #{@reflection.options[:join_table]} ON #{@reflection.klass.table_name}.#{@reflection.klass.primary_key} = #{@reflection.options[:join_table]}.#{@reflection.association_foreign_key}" 
    159159        end 
    160          
     160 
     161        # Join tables with additional columns on top of the two foreign keys must be considered ambigious unless a select 
     162        # clause has been explicitly defined. Otherwise you can get broken records back, if, say, the join column also has 
     163        # and id column, which will then overwrite the id column of the records coming back. 
     164        def finding_with_ambigious_select?(select_clause) 
     165          !select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2 
     166        end 
    161167    end 
    162168  end 
  • trunk/activerecord/lib/active_record/base.rb

    r4116 r4123  
    851851                    merge = hash[method][key] && params[key] # merge if both scopes have the same key 
    852852                    if key == :conditions && merge 
    853                       hash[method][key] = [params[key], hash[method][key]].collect{|sql| "( %s )" % sanitize_sql(sql)}.join(" AND ") 
     853                      hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ") 
    854854                    elsif key == :include && merge 
    855855                      hash[method][key] = merge_includes(hash[method][key], params[key]).uniq 
  • trunk/activerecord/test/associations_test.rb

    r3921 r4123  
    88require 'fixtures/customer' 
    99require 'fixtures/order' 
     10require 'fixtures/category' 
    1011require 'fixtures/post' 
    1112require 'fixtures/author' 
     
    10811082 
    10821083class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase 
    1083   fixtures :accounts, :companies, :developers, :projects, :developers_projects 
     1084  fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects 
    10841085   
    10851086  def test_has_and_belongs_to_many 
     
    14701471    end_sql 
    14711472  end 
     1473   
     1474  def test_updating_attributes_on_non_rich_associations 
     1475    welcome = categories(:technology).posts.first 
     1476    welcome.title = "Something else" 
     1477    assert welcome.save! 
     1478  end 
     1479   
     1480  def test_updating_attributes_on_rich_associations 
     1481    david = projects(:action_controller).developers.first 
     1482    david.name = "DHH" 
     1483    assert_raises(ActiveRecord::ReadOnlyRecord) { david.save! } 
     1484  end 
     1485 
     1486   
     1487  def test_updating_attributes_on_rich_associations_with_limited_find 
     1488    david = projects(:action_controller).developers.find(:all, :select => "developers.*").first 
     1489    david.name = "DHH" 
     1490    assert david.save! 
     1491  end 
    14721492 
    14731493  def test_join_table_alias