diff options
Diffstat (limited to 'activerecord/lib/active_record')
8 files changed, 52 insertions, 12 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 3f2b5d726e..05ce8ff0b5 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1090,6 +1090,22 @@ module ActiveRecord # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the # custom <tt>:join_table</tt> option if you need to. # + # The join table should not have a primary key or a model associated with it. You must manually generate the + # join table with a migration such as this: + # + # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration + # def self.up + # create_table :developers_projects, :id => false do |t| + # t.integer :developer_id + # t.integer :project_id + # end + # end + # + # def self.down + # drop_table :developers_projects + # end + # end + # # Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through # +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as # readonly (because we can't save changes to the additional attributes). It's strongly recommended that you upgrade any diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 177d156834..3ffc48941c 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -324,6 +324,7 @@ module ActiveRecord if Numeric === value || value !~ /[^0-9]/ !value.to_i.zero? else + return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value) !value.blank? end elsif column.number? diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 07660ebd03..680b41518c 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -129,6 +129,7 @@ module ActiveRecord base.class_eval do alias_method_chain :reload, :autosave_associations alias_method_chain :save, :autosave_associations + alias_method_chain :save!, :autosave_associations alias_method_chain :valid?, :autosave_associations %w{ has_one belongs_to has_many has_and_belongs_to_many }.each do |type| @@ -161,6 +162,17 @@ module ActiveRecord end end + # Attempts to save the record just like save_with_autosave_associations but + # will raise a RecordInvalid exception instead of returning false if the + # record is not valid. + def save_with_autosave_associations! + if valid_with_autosave_associations? + save_with_autosave_associations(false) || raise(RecordNotSaved) + else + raise RecordInvalid.new(self) + end + end + # Returns whether or not the parent, <tt>self</tt>, and any loaded autosave associations are valid. def valid_with_autosave_associations? if valid_without_autosave_associations? diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index f9168c8dc2..78c6ac2ba8 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -663,7 +663,7 @@ module ActiveRecord #:nodoc: # Returns true if a record exists in the table that matches the +id+ or - # conditions given, or false otherwise. The argument can take four forms: + # conditions given, or false otherwise. The argument can take five forms: # # * Integer - Finds the record with this primary key. # * String - Finds the record with a primary key corresponding to this @@ -672,6 +672,7 @@ module ActiveRecord #:nodoc: # (such as <tt>['color = ?', 'red']</tt>). # * Hash - Finds the record that matches these +find+-style conditions # (such as <tt>{:color => 'red'}</tt>). + # * No args - Returns false if the table is empty, true otherwise. # # For more information about specifying conditions as a Hash or Array, # see the Conditions section in the introduction to ActiveRecord::Base. @@ -685,7 +686,8 @@ module ActiveRecord #:nodoc: # Person.exists?('5') # Person.exists?(:name => "David") # Person.exists?(['name LIKE ?', "%#{query}%"]) - def exists?(id_or_conditions) + # Person.exists? + def exists?(id_or_conditions = {}) connection.select_all( construct_finder_sql( :select => "#{quoted_table_name}.#{primary_key}", @@ -1990,12 +1992,16 @@ module ActiveRecord #:nodoc: attribute_names.all? { |name| column_methods_hash.include?(name.to_sym) } end - def attribute_condition(argument) + def attribute_condition(quoted_column_name, argument) case argument - when nil then "IS ?" - when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "IN (?)" - when Range then "BETWEEN ? AND ?" - else "= ?" + when nil then "#{quoted_column_name} IS ?" + when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "#{quoted_column_name} IN (?)" + when Range then if argument.exclude_end? + "#{quoted_column_name} >= ? AND #{quoted_column_name} < ?" + else + "#{quoted_column_name} BETWEEN ? AND ?" + end + else "#{quoted_column_name} = ?" end end @@ -2305,7 +2311,7 @@ module ActiveRecord #:nodoc: table_name = connection.quote_table_name(table_name) end - "#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}" + attribute_condition("#{table_name}.#{connection.quote_column_name(attr)}", value) else sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s)) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 273f823e7f..24c734cddb 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -8,6 +8,7 @@ module ActiveRecord # An abstract definition of a column in a table. class Column TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set + FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set module Format ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index 8bfdadd0e3..5778223c74 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -86,7 +86,8 @@ module ActiveRecord # For each key in the hash that starts with the string 'new' a new model # will be instantiated. When the proc given with the <tt>:reject_if</tt> # option evaluates to +false+ for a certain attribute hash no record will - # be built for that hash. + # be built for that hash. (Rejecting new records can alternatively be done + # by utilizing the <tt>'_delete'</tt> key. Scroll down for more info.) # # params = { 'member' => { # 'name' => 'joe', 'posts_attributes' => { @@ -258,11 +259,14 @@ module ActiveRecord # If a <tt>:reject_if</tt> proc exists for this association, it will be # called with the attributes as its argument. If the proc returns a truthy # value, the record is _not_ build. + # + # Alternatively, you can specify the <tt>'_delete'</tt> key to _not_ build + # a record. See should_destroy_nested_attributes_record? for more info. def build_new_nested_attributes_record(association_name, attributes) if reject_proc = self.class.reject_new_nested_attributes_procs[association_name] return if reject_proc.call(attributes) end - send(association_name).build(attributes) + send(association_name).build(attributes) unless should_destroy_nested_attributes_record?(true, attributes) end # Assigns the attributes to the record specified by +id+. Or marks it for diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 5e45cf65ab..de199d30bf 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -99,7 +99,7 @@ module ActiveRecord define_method(:session_id=) { |session_id| self.sessid = session_id } else def self.find_by_session_id(session_id) - find :first, :conditions => ["session_id #{attribute_condition(session_id)}", session_id] + find :first, :conditions => {:session_id=>session_id} end end end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index ce93b0f270..8f3c80565e 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -744,7 +744,7 @@ module ActiveRecord if scope = configuration[:scope] Array(scope).map do |scope_item| scope_value = record.send(scope_item) - condition_sql << " AND #{record.class.quoted_table_name}.#{scope_item} #{attribute_condition(scope_value)}" + condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value) condition_params << scope_value end end |