0

I was under the impression that the custom_finder option in ActiveRecord meant that you got association extensions like .where and .order for free, for instance:

class Dog < ActiveRecord::Base
  has_many :fleas, class_name: 'Flea', 
           finder_sql: "select fleas.* from fleas where pet_type = 'dog'"
end

granted this is not a great example as the 'finder_sql' is so trivial however it illustrates the point.

Generated SQL

I would expect the following

@dog = Dog.find(5)
@dog.fleas.where('num_legs > 2')

to generate

"select fleas.* from fleas where pet_type = 'dog' AND num_legs > 2

i.e. custom finder_sql + where clause

however what it actually generates is

"SELECT "base_posts".* FROM "fleas" WHERE "fleas"."dog_id" = 5 AND (num_legs > 2)

i.e. it completely ignores the custom finder_sql and tries to join the fleas to the current dog.

If the custom finder_sql doesn't cause the association extensions to respect it then what's the point in it - it could just be a method on the object...

Peter Nixey
  • 16,187
  • 14
  • 79
  • 133

1 Answers1

0

This is true. I think that custom finder is the legacy of the previous generation of finders in Rails (before Arel && AR::Relation) and its presence in associations today is only for backward compatibility (imho). Anyway, it does not fit the ideology of AR::Relation (extensions).

By now, we have .find_by_sql() and we have :finder_sql as options for associations.

Actually now, when association has :finder_sql option, it is only used for the formation of records collection (using .find_by_sql). Association creates the AR::Relation object, loads collection (.target) and delegating AR::Relation method calls to relation object, which however was not aware of any custom SQL statements and knows only primary SQL expression. This is why:

@dog.fleas.class
#=> Array
@dog.fleas.to_sql # delegated to AR::Relation

returns primary expression "SELECT "base_posts".* FROM..." and

@dog.fleas.where("...") # delegated to AR::Relation

imposes new conditions as if there is no custom finder.

On the other hand, since .find_by_sql always returns an array, to impose new conditions could be possible using Array's methods.

 @dog.fleas.select {|r| ... } # delegated to Array
Valery Kvon
  • 4,438
  • 1
  • 20
  • 15