简体   繁体   中英

Tire gem: undefined method `detect'

I am using a few persisted Tire models in my Rails app. Searching has been working fine, using Tire.search ['index1','index2'], :load => true do ... But I now made a new index and model, and I get the following error when trying to include it in the search and access its results:

undefined method `detect' for #<AuthoredHistory:0x000001013d6a88>

I see it's coming from Tire::Results::Collection#results, down at the last line:

@response['hits']['hits'].map { |item| records[item['_type']].detect { |record| record.id.to_s == item['_id'].to_s } }

For some reason records[item['_type']] returns a Tire::Results::Collection object for my other models, but with the new class it returns an AuthoredHistory object, which is my actual model class. I saw something about this on the gem's github page, but I am not doing anything with Tire.configuration.wrapper. I am including Persistence, Search, and Callbacks modules in all indexed models.

Am I missing something? Can someone please point me in the right direction? (karmi, I'm hoping you can save me here!)

[UPDATE]

Now I'm getting somewhere... an error was occurring when only 1 result from a particular index is returned with the results. If there are 2 or more results from an index, it wraps it in Tire::Results::Collection. Now to find a hack...

[UPDATE again]

Hacky solution found! Look below for the answer...

I think you're missing the curly brace for the map before the detect. It should be this:

@response['hits']['hits'].map { |item| records[item['_type']] }.detect { |record| record.id.to_s == item['_id'].to_s }

I don't know the codebase well enough to know this for sure, but I think records[item['_type']] is going to be returning one of those AuthoredHistory objects, which don't have the detect method on them.

The detect method is used in Enumerable collections in Ruby, and that's kind of object that map returns (it'll return an Array ) object. Therefore, the curly brace was in the wrong position.

I found a hack that I believe works... not a pretty one, but that's the nature of the hack. If there is only ONE result for a particular model, the records do not return a Tire::Results::Collection object but rather just an object of the actual model, which fails on detect . So, I must check if we have a Collection or not, and if not, simply wrap it in an array. It seems to work for now, hopefully there are no ill effects down the road...

Here is the hack... this replaces the problematic line that I posted in the question:

@response['hits']['hits'].map do |item|
  collection = records[item['_type']].is_a?(Tire::Results::Collection) ?
    records[item['_type']] :
    [records[item['_type']]]
  collection.detect { |record| record.id.to_s == item['_id'].to_s }
end

ALSO! I had done a hack before to account for when the search results as a whole only returned one item. I had to insert this line right before the same problematic line above:

return [records[@response['hits']['hits'].first['_type']]] if @response['hits']['hits'].size == 1

This should be now fixed in commit 44eda24 . See also issue #725 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM