lib/hobo/scopes/automatic_scopes.rb in hobo-1.1.0.pre2 vs lib/hobo/scopes/automatic_scopes.rb in hobo-1.1.0.pre3
- old
+ new
@@ -265,11 +265,34 @@
klass = @klass
def_scope do |*args|
field, asc = args
type = klass.attr_type(field)
if type.nil? #a virtual attribute from an SQL alias, e.g., 'total' from 'COUNT(*) AS total'
- colspec = "#{field}" # don't prepend the table name
+ # can also be has_many association, let's check it out
+ _, assoc, count = *field._?.match(/^([a-z_]+)(?:\.([a-z_]+))?/)
+ refl = klass.attr_type(assoc)
+
+ if refl.respond_to?(:primary_key_name) && refl.macro == :has_many && count._?.upcase == 'COUNT'
+ owner_primary_key = "#{klass.quoted_table_name}.#{klass.primary_key}"
+ # now we have :has_many association in refl, is this a through association?
+ if (through = refl.through_reflection) && (source = refl.source_reflection)
+ # has_many through association was found and now we have a few variants:
+ # 1) owner.has_many -> through.belongs_to <- source.has_many (many to many, source.macro == :belongs_to )
+ # 2) owner.has_many -> through.has_many -> source.belongs_to (many to one through table, source.macro == :has_many)
+ colspec = "(SELECT COUNT(*) AS count_all FROM #{refl.quoted_table_name} INNER JOIN #{through.quoted_table_name}" +
+ " ON #{source.quoted_table_name}.#{source.macro == :belongs_to ? source.klass.primary_key : through.association_foreign_key}" +
+ " = #{through.quoted_table_name}.#{source.macro == :belongs_to ? source.association_foreign_key : through.klass.primary_key}" +
+ " WHERE #{through.quoted_table_name}.#{through.primary_key_name} = #{owner_primary_key} )"
+ else
+ # simple many to one (has_many -> belongs_to) association
+ colspec = "(SELECT COUNT(*) as count_all FROM #{refl.quoted_table_name}" +
+ " WHERE #{refl.quoted_table_name}.#{refl.primary_key_name} = #{owner_primary_key})"
+ end
+
+ else
+ colspec = "#{field}" # don't prepend the table name
+ end
elsif type.respond_to?(:name_attribute) && (name = type.name_attribute)
include = field
colspec = "#{type.table_name}.#{name}"
else
colspec = "#{klass.table_name}.#{field}"
@@ -277,9 +300,14 @@
{ :order => "#{colspec} #{asc._?.upcase}", :include => include }
end
when "include"
+ def_scope do |inclusions|
+ { :include => inclusions }
+ end
+
+ when "includes"
def_scope do |inclusions|
{ :include => inclusions }
end
when "search"