diff options
Diffstat (limited to 'activerecord/lib')
3 files changed, 74 insertions, 35 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 285b4065b1..7e53f8958a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -507,7 +507,7 @@ module ActiveRecord raise NotImplementedError, "change_column_default is not implemented" end - # Sets or removes a +NOT NULL+ constraint on a column. The +null+ flag + # Sets or removes a <tt>NOT NULL</tt> constraint on a column. The +null+ flag # indicates whether the value can be +NULL+. For example # # change_column_null(:users, :nickname, false) @@ -519,7 +519,7 @@ module ActiveRecord # allows them to be +NULL+ (drops the constraint). # # The method accepts an optional fourth argument to replace existing - # +NULL+s with some other value. Use that one when enabling the + # <tt>NULL</tt>s with some other value. Use that one when enabling the # constraint if needed, since otherwise those rows would not be valid. # # Please note the fourth argument does not set a column's default. diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 4e0fc407bc..65ec356735 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -175,6 +175,20 @@ module ActiveRecord end end + def inverse_of + return unless inverse_name + + @inverse_of ||= klass._reflect_on_association inverse_name + end + + def check_validity_of_inverse! + unless polymorphic? + if has_inverse? && inverse_of.nil? + raise InverseOfAssociationNotFoundError.new(self) + end + end + end + # This shit is nasty. We need to avoid the following situation: # # * An associated record is deleted via record.destroy @@ -377,14 +391,6 @@ module ActiveRecord check_validity_of_inverse! end - def check_validity_of_inverse! - unless polymorphic? - if has_inverse? && inverse_of.nil? - raise InverseOfAssociationNotFoundError.new(self) - end - end - end - def check_preloadable! return unless scope @@ -436,12 +442,6 @@ module ActiveRecord inverse_name end - def inverse_of - return unless inverse_name - - @inverse_of ||= klass._reflect_on_association inverse_name - end - def polymorphic_inverse_of(associated_class) if has_inverse? if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of]) @@ -924,6 +924,8 @@ module ActiveRecord klass.primary_key || raise(UnknownPrimaryKey.new(klass)) end + def inverse_name; delegate_reflection.send(:inverse_name); end + private def derive_class_name # get the class_name of the belongs_to association of the through reflection diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index 32f4229977..7f6664ea50 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -4,7 +4,7 @@ module ActiveRecord module ClassMethods # Used to sanitize objects before they're used in an SQL SELECT statement. Delegates to <tt>connection.quote</tt>. - def sanitize(object) #:nodoc: + def sanitize(object) # :nodoc: connection.quote(object) end alias_method :quote_value, :sanitize @@ -13,8 +13,15 @@ module ActiveRecord # Accepts an array or string of SQL conditions and sanitizes # them into a valid SQL fragment for a WHERE clause. - # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" - # "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'" + # + # sanitize_sql_for_conditions(["name=? and group_id=?", "foo'bar", 4]) + # # => "name='foo''bar' and group_id=4" + # + # sanitize_sql_for_conditions(["name='%s' and group_id='%s'", "foo'bar", 4]) + # # => "name='foo''bar' and group_id='4'" + # + # sanitize_sql_for_conditions("name='foo''bar' and group_id='4'") + # # => "name='foo''bar' and group_id='4'" def sanitize_sql_for_conditions(condition) return nil if condition.blank? @@ -28,7 +35,15 @@ module ActiveRecord # Accepts an array, hash, or string of SQL conditions and sanitizes # them into a valid SQL fragment for a SET clause. - # { name: nil, group_id: 4 } returns "name = NULL , group_id='4'" + # + # sanitize_sql_for_assignment(["name=? and group_id=?", nil, 4]) + # # => "name=NULL and group_id=4" + # + # Post.send(:sanitize_sql_for_assignment, { name: nil, group_id: 4 }) + # # => "`posts`.`name` = NULL, `posts`.`group_id` = 4" + # + # sanitize_sql_for_assignment("name=NULL and group_id='4'") + # # => "name=NULL and group_id='4'" def sanitize_sql_for_assignment(assignments, default_table_name = self.table_name) case assignments when Array; sanitize_sql_array(assignments) @@ -40,14 +55,18 @@ module ActiveRecord # Accepts a hash of SQL conditions and replaces those attributes # that correspond to a +composed_of+ relationship with their expanded # aggregate attribute values. + # # Given: - # class Person < ActiveRecord::Base - # composed_of :address, class_name: "Address", - # mapping: [%w(address_street street), %w(address_city city)] - # end + # + # class Person < ActiveRecord::Base + # composed_of :address, class_name: "Address", + # mapping: [%w(address_street street), %w(address_city city)] + # end + # # Then: - # { address: Address.new("813 abc st.", "chicago") } - # # => { address_street: "813 abc st.", address_city: "chicago" } + # + # { address: Address.new("813 abc st.", "chicago") } + # # => { address_street: "813 abc st.", address_city: "chicago" } def expand_hash_conditions_for_aggregates(attrs) expanded_attrs = {} attrs.each do |attr, value| @@ -68,8 +87,9 @@ module ActiveRecord end # Sanitizes a hash of attribute/value pairs into SQL conditions for a SET clause. - # { status: nil, group_id: 1 } - # # => "status = NULL , group_id = 1" + # + # sanitize_sql_hash_for_assignment({ status: nil, group_id: 1 }, "posts") + # # => "`posts`.`status` = NULL, `posts`.`group_id` = 1" def sanitize_sql_hash_for_assignment(attrs, table) c = connection attrs.map do |attr, value| @@ -79,7 +99,19 @@ module ActiveRecord end # Sanitizes a +string+ so that it is safe to use within an SQL - # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%" + # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%". + # + # sanitize_sql_like("100%") + # # => "100\\%" + # + # sanitize_sql_like("snake_cased_string") + # # => "snake\\_cased\\_string" + # + # sanitize_sql_like("100%", "!") + # # => "100!%" + # + # sanitize_sql_like("snake_cased_string", "!") + # # => "snake!_cased!_string" def sanitize_sql_like(string, escape_character = "\\") pattern = Regexp.union(escape_character, "%", "_") string.gsub(pattern) { |x| [escape_character, x].join } @@ -87,7 +119,12 @@ module ActiveRecord # Accepts an array of conditions. The array has each value # sanitized and interpolated into the SQL statement. - # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" + # + # sanitize_sql_array(["name=? and group_id=?", "foo'bar", 4]) + # # => "name='foo''bar' and group_id=4" + # + # sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4]) + # # => "name='foo''bar' and group_id='4'" def sanitize_sql_array(ary) statement, *values = ary if values.first.is_a?(Hash) && statement =~ /:\w+/ @@ -101,7 +138,7 @@ module ActiveRecord end end - def replace_bind_variables(statement, values) #:nodoc: + def replace_bind_variables(statement, values) # :nodoc: raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size) bound = values.dup c = connection @@ -110,7 +147,7 @@ module ActiveRecord end end - def replace_bind_variable(value, c = connection) #:nodoc: + def replace_bind_variable(value, c = connection) # :nodoc: if ActiveRecord::Relation === value value.to_sql else @@ -118,7 +155,7 @@ module ActiveRecord end end - def replace_named_bind_variables(statement, bind_vars) #:nodoc: + def replace_named_bind_variables(statement, bind_vars) # :nodoc: statement.gsub(/(:?):([a-zA-Z]\w*)/) do |match| if $1 == ':' # skip postgresql casts match # return the whole match @@ -130,7 +167,7 @@ module ActiveRecord end end - def quote_bound_value(value, c = connection) #:nodoc: + def quote_bound_value(value, c = connection) # :nodoc: if value.respond_to?(:map) && !value.acts_like?(:string) if value.respond_to?(:empty?) && value.empty? c.quote(nil) @@ -142,7 +179,7 @@ module ActiveRecord end end - def raise_if_bind_arity_mismatch(statement, expected, provided) #:nodoc: + def raise_if_bind_arity_mismatch(statement, expected, provided) # :nodoc: unless expected == provided raise PreparedStatementInvalid, "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}" end |