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

Ticket #6896: attr_readonly.diff

File attr_readonly.diff, 7.4 kB (added by dcmanges, 2 years ago)
  • test/associations_test.rb

    old new  
    11261126    assert_equal 0, Topic.find(t1.id).replies.size 
    11271127    assert_equal 0, Topic.find(t2.id).replies.size 
    11281128  end 
     1129   
     1130  def test_belongs_to_counter_after_save 
     1131    topic = Topic.create("title" => "monday night") 
     1132    topic.replies.create("title" => "re: monday night", "content" => "football") 
     1133    assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 
    11291134 
     1135    topic.save 
     1136    assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 
     1137  end 
     1138 
     1139  def test_belongs_to_counter_after_update_attributes 
     1140    topic = Topic.create("title" => "37s") 
     1141    topic.replies.create("title" => "re: 37s", "content" => "rails") 
     1142    assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 
     1143 
     1144    topic.update_attributes("title" => "37signals") 
     1145    assert_equal 1, Topic.find(topic.id).send(:read_attribute, "replies_count") 
     1146  end 
     1147 
    11301148  def test_assignment_before_parent_saved 
    11311149    client = Client.find(:first) 
    11321150    apple = Firm.new("name" => "Apple") 
  • test/base_test.rb

    old new  
    4747  attr_accessible :phone_number 
    4848end 
    4949 
     50class ReadonlyTitlePost < Post 
     51  attr_readonly :title 
     52end 
     53 
    5054class Booleantest < ActiveRecord::Base; end 
    5155 
    5256class Task < ActiveRecord::Base 
     
    767771    assert_nil TightDescendant.protected_attributes 
    768772    assert_equal [ :name, :address, :phone_number  ], TightDescendant.accessible_attributes 
    769773  end 
     774   
     775  def test_readonly_attributes 
     776    assert_equal [ :title ], ReadonlyTitlePost.readonly_attributes 
     777     
     778    post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable") 
     779    post.reload 
     780    assert_equal "cannot change this", post.title 
     781     
     782    post.update_attributes(:title => "try to change", :body => "changed") 
     783    post.reload 
     784    assert_equal "cannot change this", post.title 
     785    assert_equal "changed", post.body 
     786  end 
    770787 
    771788  def test_multiparameter_attributes_on_date 
    772789    attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" } 
     
    11361153  end 
    11371154 
    11381155  def test_increment_attribute 
    1139     assert_equal 1, topics(:first).replies_coun
    1140     topics(:first).increment! :replies_coun
    1141     assert_equal 2, topics(:first, :reload).replies_count 
    1142      
    1143     topics(:first).increment(:replies_count).increment!(:replies_count) 
    1144     assert_equal 4, topics(:first, :reload).replies_coun
     1156    assert_equal 50, accounts(:signals37).credit_limi
     1157    accounts(:signals37).increment! :credit_limi
     1158    assert_equal 51, accounts(:signals37, :reload).credit_limit     
     1159 
     1160    accounts(:signals37).increment(:credit_limit).increment!(:credit_limit) 
     1161    assert_equal 53, accounts(:signals37, :reload).credit_limi
    11451162  end 
    11461163   
    11471164  def test_increment_nil_attribute 
     
    11511168  end 
    11521169   
    11531170  def test_decrement_attribute 
    1154     topics(:first).increment(:replies_count).increment!(:replies_count) 
    1155     assert_equal 3, topics(:first).replies_count 
    1156      
    1157     topics(:first).decrement!(:replies_count) 
    1158     assert_equal 2, topics(:first, :reload).replies_count 
     1171    assert_equal 50, accounts(:signals37).credit_limit 
    11591172 
    1160     topics(:first).decrement(:replies_count).decrement!(:replies_count) 
    1161     assert_equal 0, topics(:first, :reload).replies_count 
     1173    accounts(:signals37).decrement!(:credit_limit) 
     1174    assert_equal 49, accounts(:signals37, :reload).credit_limit 
     1175   
     1176    accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit) 
     1177    assert_equal 47, accounts(:signals37, :reload).credit_limit 
    11621178  end 
    11631179   
    11641180  def test_toggle_attribute 
  • lib/active_record/associations.rb

    old new  
    739739          module_eval( 
    740740            "before_destroy '#{reflection.name}.class.decrement_counter(\"#{cache_column}\", #{reflection.primary_key_name})" + 
    741741            " unless #{reflection.name}.nil?'" 
    742           )           
     742          ) 
     743           
     744          module_eval( 
     745            "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name})" 
     746          ) 
    743747        end 
    744748      end 
    745749 
  • lib/active_record/base.rb

    old new  
    569569        read_inheritable_attribute("attr_accessible") 
    570570      end 
    571571 
     572      # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards. 
     573      def attr_readonly(*attributes) 
     574        write_inheritable_array("attr_readonly", attributes - (readonly_attributes || [])) 
     575      end 
    572576 
     577      # Returns an array of all the attributes that have been specified as readonly. 
     578      def readonly_attributes 
     579        read_inheritable_attribute("attr_readonly") 
     580      end 
     581 
    573582      # Specifies that the attribute by the name of +attr_name+ should be serialized before saving to the database and unserialized 
    574583      # after loading from the database. The serialization is done through YAML. If +class_name+ is specified, the serialized 
    575584      # object must be of that class on retrieval or +SerializationTypeMismatch+ will be raised. 
     
    17831792      def update 
    17841793        connection.update( 
    17851794          "UPDATE #{self.class.table_name} " + 
    1786           "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " + 
     1795          "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false))} " + 
    17871796          "WHERE #{self.class.primary_key} = #{quote_value(id)}", 
    17881797          "#{self.class.name} Update" 
    17891798        ) 
     
    19952004          attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,"").intern) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) } 
    19962005        end 
    19972006      end 
     2007       
     2008      # Removes attributes which have been marked as readonly. 
     2009      def remove_readonly_attributes(attributes) 
     2010        unless self.class.readonly_attributes.nil? 
     2011          attributes.reject { |key, value| self.class.readonly_attributes.include?(key.gsub(/\(.+/,"").intern) } 
     2012        else 
     2013          attributes 
     2014        end 
     2015      end 
    19982016 
    19992017      # The primary key and inheritance column can never be set by mass-assignment for security reasons. 
    20002018      def attributes_protected_by_default 
     
    20052023 
    20062024      # Returns copy of the attributes hash where all the values have been safely quoted for use in 
    20072025      # an SQL statement. 
    2008       def attributes_with_quotes(include_primary_key = true
    2009         attributes.inject({}) do |quoted, (name, value)| 
     2026      def attributes_with_quotes(include_primary_key = true, include_readonly_attributes = true
     2027        quoted = attributes.inject({}) do |quoted, (name, value)| 
    20102028          if column = column_for_attribute(name) 
    20112029            quoted[name] = quote_value(value, column) unless !include_primary_key && column.primary 
    20122030          end 
    20132031          quoted 
    20142032        end 
     2033        include_readonly_attributes ? quoted : remove_readonly_attributes(quoted) 
    20152034      end 
    20162035 
    20172036      # Quote strings appropriately for SQL statements.