searchlogic
searchlogic copied to clipboard
Searchlogic 2.4.22 generates a full table scan when :including associated models with a boolean column in a to_json call
Consider the following bloggish object model.
# has a boolean field called 'active'
class Content < ActiveRecord::Base
has_many :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :content
validates_presence_of :category_id, :content_id
end
Categorization.first.to_json(:include => :content)
# generates the following SQL queries
# Categorization Load (21.8ms) SELECT * FROM "categorizations" LIMIT 1
# Content Load (0.4ms) SELECT * FROM "contents" WHERE ("contents"."id" = 1)
# Content Load (0.3ms) SELECT * FROM "contents" WHERE ("contents"."active" = '1')
The last query, the full table scan, is not good. Especially if you have a large table and are trying to serialize all of them to json.
I'm not sure where/what is causing this, but I'll try to figure out what's going on here and submit a patch.
After stepping through rails, I've found that the additional query occurs here in activerecord/lib/serialization.rb:76. Specifically, this happens when rails tries to serialize the associated 'content' object. This is with active record 2.3.5.For convenience:
def serializable_record
returning(serializable_record = {}) do
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
add_includes do |association, records, opts|
if records.is_a?(Enumerable)
serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
else
serializable_record[association] = self.class.new(records, opts).serializable_record
end
end
end
end
So it looks like every attribute being serialized during the to_json call is ending up in the send_with_searchlogic method in lib/searchlogic/active_record/association_proxy.rb:10 (http://github.com/binarylogic/searchlogic/blob/v2.4.22/lib/searchlogic/active_record/association_proxy.rb#L10).
The problem is that searchlogic automatically generates named scopes for all boolean columns, so when it hits this method with the active field, it calls proxy_reflection.klass.send(method, *args) on line 12, which I believe is generating the query.
Any ideas as to why a to_json call would end up here?