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

Changeset 9157

Show
Ignore:
Timestamp:
03/31/08 01:10:04 (2 years ago)
Author:
bitsweat
Message:

Partial updates include only unsaved attributes. Off by default; set YourClass.partial_updates = true to enable.

Files:

Legend:

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

    r9150 r9157  
    11*SVN* 
     2 
     3* Partial updates include only unsaved attributes. Off by default; set YourClass.partial_updates = true to enable.  [Jeremy Kemper] 
    24 
    35* Removing unnecessary uses_tzinfo helper from tests, given that TZInfo is now bundled [Geoff Buesing] 
  • trunk/activerecord/lib/active_record/aggregations.rb

    r8671 r9157  
    175175            define_method("#{name}=") do |part| 
    176176              if part.nil? && allow_nil 
    177                 mapping.each { |pair| @attributes[pair.first] = nil } 
     177                mapping.each { |pair| self[pair.first] = nil } 
    178178                instance_variable_set("@#{name}", nil) 
    179179              else 
    180180                part = conversion.call(part) unless part.is_a?(class_name.constantize) || conversion.nil? 
    181                 mapping.each { |pair| @attributes[pair.first] = part.send(pair.last) } 
     181                mapping.each { |pair| self[pair.first] = part.send(pair.last) } 
    182182                instance_variable_set("@#{name}", part.freeze) 
    183183              end 
  • trunk/activerecord/lib/active_record/base.rb

    r9122 r9157  
    24082408      # Updates the associated record with values matching those of the instance attributes. 
    24092409      # Returns the number of affected rows. 
    2410       def update 
    2411         quoted_attributes = attributes_with_quotes(false, false
     2410      def update(attribute_names = @attributes.keys) 
     2411        quoted_attributes = attributes_with_quotes(false, false, attribute_names
    24122412        return 0 if quoted_attributes.empty? 
    24132413        connection.update( 
     
    25012501      # Returns a copy of the attributes hash where all the values have been safely quoted for use in 
    25022502      # an SQL statement. 
    2503       def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true
     2503      def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true, attribute_names = @attributes.keys
    25042504        quoted = {} 
    25052505        connection = self.class.connection 
    2506         @attributes.each_pair do |name, value| 
     2506        attribute_names.each do |name| 
    25072507          if column = column_for_attribute(name) 
    25082508            quoted[name] = connection.quote(read_attribute(name), column) unless !include_primary_key && column.primary 
  • trunk/activerecord/lib/active_record/callbacks.rb

    r8664 r9157  
    230230    def after_update() end 
    231231 
    232     def update_with_callbacks #:nodoc: 
     232    def update_with_callbacks(*args) #:nodoc: 
    233233      return false if callback(:before_update) == false 
    234       result = update_without_callbacks 
     234      result = update_without_callbacks(*args) 
    235235      callback(:after_update) 
    236236      result 
  • trunk/activerecord/lib/active_record/dirty.rb

    r9139 r9157  
    2929  #   person.changed        # => ['name'] 
    3030  #   person.changes        # => { 'name' => ['Bill', 'bob'] } 
     31  # 
     32  # Before modifying an attribute in-place: 
     33  #   person.name_will_change! 
     34  #   person.name << 'by' 
     35  #   person.name_change    # => ['uncle bob', 'uncle bobby'] 
    3136  module Dirty 
    3237    def self.included(base) 
    33       base.attribute_method_suffix '_changed?', '_change', '_was' 
     38      base.attribute_method_suffix '_changed?', '_change', '_will_change!', '_was' 
    3439      base.alias_method_chain :write_attribute, :dirty 
    3540      base.alias_method_chain :save,            :dirty 
    3641      base.alias_method_chain :save!,           :dirty 
     42      base.alias_method_chain :update,          :dirty 
     43 
     44      base.superclass_delegating_accessor :partial_updates 
     45      base.partial_updates = true 
    3746    end 
    3847 
     
    8291      end 
    8392 
     93      # Handle *_changed? for method_missing. 
     94      def attribute_changed?(attr) 
     95        changed_attributes.include?(attr) 
     96      end 
     97 
     98      # Handle *_change for method_missing. 
     99      def attribute_change(attr) 
     100        [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) 
     101      end 
     102 
     103      # Handle *_was for method_missing. 
     104      def attribute_was(attr) 
     105        attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) 
     106      end 
     107 
     108      # Handle *_will_change! for method_missing. 
     109      def attribute_will_change!(attr) 
     110        changed_attributes[attr] = clone_attribute_value(:read_attribute, attr) 
     111      end 
    84112 
    85113      # Wrap write_attribute to remember original attribute value. 
     
    89117        # The attribute already has an unsaved change. 
    90118        unless changed_attributes.include?(attr) 
    91           old = read_attribute(attr) 
     119          old = clone_attribute_value(:read_attribute, attr) 
    92120 
    93121          # Remember the original value if it's different. 
     
    104132      end 
    105133 
    106  
    107       # Handle *_changed? for method_missing. 
    108       def attribute_changed?(attr) 
    109         changed_attributes.include?(attr) 
    110       end 
    111  
    112       # Handle *_change for method_missing. 
    113       def attribute_change(attr) 
    114         [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) 
    115       end 
    116  
    117       # Handle *_was for method_missing. 
    118       def attribute_was(attr) 
    119         attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) 
     134      def update_with_dirty 
     135        if partial_updates? 
     136          update_without_dirty(changed) 
     137        else 
     138          update_without_dirty 
     139        end 
    120140      end 
    121141  end 
  • trunk/activerecord/lib/active_record/locking/optimistic.rb

    r8395 r9157  
    6767        end 
    6868 
    69         def update_with_lock #:nodoc: 
    70           return update_without_lock unless locking_enabled? 
     69        def update_with_lock(attribute_names = @attributes.keys) #:nodoc: 
     70          return update_without_lock(attribute_names) unless locking_enabled? 
    7171 
    7272          lock_col = self.class.locking_column 
     
    7474          send(lock_col + '=', previous_value + 1) 
    7575 
     76          attribute_names += [lock_col] 
     77          attribute_names.uniq! 
     78 
    7679          begin 
    7780            affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking") 
    7881              UPDATE #{self.class.table_name} 
    79               SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false))} 
     82              SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false, attribute_names))} 
    8083              WHERE #{self.class.primary_key} = #{quote_value(id)} 
    8184              AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)} 
  • trunk/activerecord/lib/active_record/timestamp.rb

    r9093 r9157  
    3030      end 
    3131 
    32       def update_with_timestamps #:nodoc: 
     32      def update_with_timestamps(*args) #:nodoc: 
    3333        if record_timestamps 
    3434          t = self.class.default_timezone == :utc ? Time.now.utc : Time.now 
     
    3636          write_attribute('updated_on', t) if respond_to?(:updated_on) 
    3737        end 
    38         update_without_timestamps 
     38        update_without_timestamps(*args) 
    3939      end 
    4040  end 
  • trunk/activerecord/test/cases/associations_test.rb

    r9110 r9157  
    450450  def test_not_resaved_when_unchanged 
    451451    firm = Firm.find(:first, :include => :account) 
     452    firm.name += '-changed' 
    452453    assert_queries(1) { firm.save! } 
    453454 
    454455    firm = Firm.find(:first) 
    455456    firm.account = Account.find(:first) 
    456     assert_queries(1) { firm.save! } 
     457    assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! } 
    457458 
    458459    firm = Firm.find(:first).clone 
  • trunk/activerecord/test/cases/base_test.rb

    r9150 r9157  
    154154    assert_equal 2, Topic.find(topic.id).content["two"] 
    155155 
     156    topic.content_will_change! 
    156157    topic.content["three"] = 3 
    157158    topic.save 
  • trunk/activerecord/test/cases/dirty_test.rb

    r9139 r9157  
    22require 'models/topic'    # For booleans 
    33require 'models/pirate'   # For timestamps 
     4require 'models/parrot' 
    45 
    56class Pirate # Just reopening it, not defining it 
     
    2021end 
    2122 
    22 class DirtyTest < Test::Unit::TestCase 
     23class DirtyTest < ActiveRecord::TestCase 
    2324  def test_attribute_changes 
    2425    # New record - no changes. 
     
    4445  end 
    4546 
    46   # Rewritten from original tests to use AR 
    4747  def test_object_should_be_changed_if_any_attribute_is_changed 
    4848    pirate = Pirate.new 
     
    6363  end 
    6464 
     65  def test_attribute_will_change! 
     66    pirate = Pirate.create!(:catchphrase => 'arr') 
     67 
     68    pirate.catchphrase << ' matey' 
     69    assert !pirate.catchphrase_changed? 
     70 
     71    assert pirate.catchphrase_will_change! 
     72    assert pirate.catchphrase_changed? 
     73    assert_equal ['arr matey', 'arr matey'], pirate.catchphrase_change 
     74 
     75    pirate.catchphrase << '!' 
     76    assert pirate.catchphrase_changed? 
     77    assert_equal ['arr matey', 'arr matey!'], pirate.catchphrase_change 
     78  end 
     79 
     80  def test_association_assignment_changes_foreign_key 
     81    pirate = Pirate.create! 
     82    pirate.parrot = Parrot.create! 
     83    assert pirate.changed? 
     84    assert_equal %w(parrot_id), pirate.changed 
     85  end 
     86 
    6587  def test_attribute_should_be_compared_with_type_cast 
    6688    topic = Topic.new 
     
    7597    assert !topic.approved_changed? 
    7698  end 
     99 
     100  def test_partial_update 
     101    pirate = Pirate.new(:catchphrase => 'foo') 
     102 
     103    with_partial_updates Pirate, false do 
     104      assert_queries(2) { 2.times { pirate.save! } } 
     105    end 
     106 
     107    with_partial_updates Pirate, true do 
     108      assert_queries(0) { 2.times { pirate.save! } } 
     109    end 
     110  end 
     111 
     112  private 
     113    def with_partial_updates(klass, on = true) 
     114      old = klass.partial_updates? 
     115      klass.partial_updates = on 
     116      yield 
     117    ensure 
     118      klass.partial_updates = old 
     119    end 
    77120end 
  • trunk/activerecord/test/cases/query_cache_test.rb

    r8681 r9157  
    8383 
    8484    Task.cache do 
    85       Task.find(1).save! 
     85      task = Task.find(1) 
     86      task.starting = Time.now.utc 
     87      task.save! 
    8688    end 
    8789  end 
  • trunk/railties/lib/rails_generator/generators/applications/app/app_generator.rb

    r9134 r9157  
    6262      # Initializers 
    6363      m.template "configs/initializers/inflections.rb", "config/initializers/inflections.rb" 
    64       m.template "configs/initializers/mime_types.rb",  "config/initializers/mime_types.rb" 
     64      m.template "configs/initializers/mime_types.rb", "config/initializers/mime_types.rb" 
     65      m.template "configs/initializers/new_in_rails_3.rb", "config/initializers/new_in_rails_3.rb" 
    6566 
    6667      # Environments