aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-09-10 21:10:01 +0100
committerJon Leighton <j@jonathanleighton.com>2011-09-13 00:01:58 +0100
commit50d395f96ea05da1e02459688e94bff5872c307b (patch)
treec3856d526d35477131bb0bde1285a80fbb07fc4e /activerecord/lib
parent8667d3aeb64dd8dba463ace364534326411bb46c (diff)
downloadrails-50d395f96ea05da1e02459688e94bff5872c307b.tar.gz
rails-50d395f96ea05da1e02459688e94bff5872c307b.tar.bz2
rails-50d395f96ea05da1e02459688e94bff5872c307b.zip
Raise error when using write_attribute with a non-existent attribute.
Previously we would just silently write the attribute. This can lead to subtle bugs (for example, see the change in AutosaveAssociation where a through association would wrongly gain an attribute. Also, ensuring that we never gain any new attributes after initialization will allow me to reduce our dependence on method_missing.
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb10
-rw-r--r--activerecord/lib/active_record/autosave_association.rb5
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/timestamp.rb4
4 files changed, 15 insertions, 6 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 5621b44c8c..e9cdb130db 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -28,12 +28,16 @@ module ActiveRecord
# for fixnum and float columns are turned into +nil+.
def write_attribute(attr_name, value)
attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == 'id'
+ attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
@attributes_cache.delete(attr_name)
- if (column = column_for_attribute(attr_name)) && column.number?
+ column = column_for_attribute(attr_name)
+
+ if column && column.number?
@attributes[attr_name] = convert_number_column_value(value)
- else
+ elsif column || @attributes.has_key?(attr_name)
@attributes[attr_name] = value
+ else
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
end
end
alias_method :raw_write_attribute, :write_attribute
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 085fdba639..056170d82a 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -370,7 +370,10 @@ module ActiveRecord
else
key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
if autosave != false && (new_record? || record.new_record? || record[reflection.foreign_key] != key || autosave)
- record[reflection.foreign_key] = key
+ unless reflection.through_reflection
+ record[reflection.foreign_key] = key
+ end
+
saved = record.save(:validate => !autosave)
raise ActiveRecord::Rollback if !saved && autosave
saved
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 2dac9ea0fb..5e65e46a7d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -314,7 +314,7 @@ module ActiveRecord
new_id = self.class.unscoped.insert attributes_values
- self.id ||= new_id
+ self.id ||= new_id if self.class.primary_key
IdentityMap.add(self) if IdentityMap.enabled?
@new_record = false
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index cccac6ffd7..4d5e469a7f 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -48,7 +48,9 @@ module ActiveRecord
current_time = current_time_from_proper_timezone
all_timestamp_attributes.each do |column|
- write_attribute(column.to_s, current_time) if respond_to?(column) && self.send(column).nil?
+ if respond_to?(column) && respond_to?("#{column}=") && self.send(column).nil?
+ write_attribute(column.to_s, current_time)
+ end
end
end