aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/table_metadata.rb
diff options
context:
space:
mode:
authorSean Griffin <sean@thoughtbot.com>2014-12-26 16:51:01 -0700
committerSean Griffin <sean@thoughtbot.com>2014-12-26 16:54:12 -0700
commita11a8ff7840cd5c5ebb881aac61be9771b07b3ba (patch)
tree1c9fe6fbeb46649ebcb079649163f510d71c52ca /activerecord/lib/active_record/table_metadata.rb
parent5f521cbff3c8a46cfc8e16b234294a20c285d00d (diff)
downloadrails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.tar.gz
rails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.tar.bz2
rails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.zip
Fall back to type casting from the connection adapter
There are several valid cases where right now we can't determine the association's class in a call to `where`. In these cases, we can fall back to casting by looking up the column from the connection adapter (which is what happens right now when we fall through to Arel) This is ugly, and since we're trying to separate the concept of a type from a column, I'd like to remove it in the future. The problem basically comes down to this: Liquid.joins(molecules: :electrons) .where("molecules.name" => "something", "electrons.name" => "something") The hash in this case will turn into: { molecules: { name: "something" }, electrons: { name: "something" }, } What we actually need is: { molecules: { name: "something", electrons: { name: "something" }, } } /cc @mrgilman
Diffstat (limited to 'activerecord/lib/active_record/table_metadata.rb')
-rw-r--r--activerecord/lib/active_record/table_metadata.rb72
1 files changed, 70 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index 811e6964a9..e60bf55021 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -33,12 +33,19 @@ module ActiveRecord
end
def associated_table(table_name)
+ return self if table_name == arel_table.name
+
arel_table = Arel::Table.new(table_name)
association = klass._reflect_on_association(table_name)
if association && !association.polymorphic?
- klass = association.klass
+ association_klass = association.klass
+ end
+
+ if association
+ TableMetadata.new(association_klass, arel_table, association)
+ else
+ ConnectionAdapterTable.new(klass.connection, arel_table)
end
- TableMetadata.new(klass, arel_table, association)
end
def polymorphic_association?
@@ -49,4 +56,65 @@ module ActiveRecord
attr_reader :klass, :arel_table, :association
end
+
+ # FIXME: We want to get rid of this class. The connection adapter does not
+ # have sufficient knowledge about types, as they could be provided by or
+ # overriden by the ActiveRecord::Base subclass. The case where you reach this
+ # class is if you do a query like:
+ #
+ # Liquid.joins(molecules: :electrons)
+ # .where("molecules.name" => "something", "electrons.name" => "something")
+ #
+ # Since we don't know that we can get to electrons through molecules
+ class ConnectionAdapterTable # :nodoc:
+ def initialize(connection, arel_table)
+ @connection = connection
+ @arel_table = arel_table
+ end
+
+ def type_cast_for_database(attribute_name, value)
+ return value if value.is_a?(Arel::Nodes::BindParam)
+ type = type_for(attribute_name)
+ Arel::Nodes::Quoted.new(type.type_cast_for_database(value))
+ end
+
+ def resolve_column_aliases(hash)
+ hash
+ end
+
+ def arel_attribute(column_name)
+ arel_table[column_name]
+ end
+
+ def associated_with?(*)
+ false
+ end
+
+ def associated_table(table_name)
+ arel_table = Arel::Table.new(table_name)
+ ConnectionAdapterTable.new(klass.connection, arel_table)
+ end
+
+ def polymorphic_association?
+ false
+ end
+
+ protected
+
+ attr_reader :connection, :arel_table
+
+ private
+
+ def type_for(attribute_name)
+ if connection.schema_cache.table_exists?(arel_table.name)
+ column_for(attribute_name).cast_type
+ else
+ Type::Value.new
+ end
+ end
+
+ def column_for(attribute_name)
+ connection.schema_cache.columns_hash(arel_table.name)[attribute_name.to_s]
+ end
+ end
end