Search & filter on model collection from a controller

Hello all,

I’m trying to work through a feature and I’m afraid that I’m getting stuck. I have an app where users can purchase icon sets. A purchase has many icons_sets (through a join) and a purchase belongs to a user.

In a dashboard I have a list of purchases that is both searchable and filterable by a timeframe (today, this week, last week, etc). Normally I wouldn’t have trouble to implement one or the other, and I’ve implemented something similar using a tool like Elasticsearch, but I feel that would be overkill.

Gist: https://gist.github.com/seanwash/65b39a4491d48f596ebf

I know that I need to use a class method such as Purchase.search_and_filter so that I can have a collection to actually search and filter. I also wanted to separate this out into two methods to keep things readable and organized.

The first problem I’m running into is that calling the method filter_by_timeframe throws an error:

undefined method `filter_by_timeframe' for #<Purchase::ActiveRecord_Relation:0x007f929f5644b8>

In my understanding, I’m wanting to send a collection through search_and_filter, doing a search if needed, and then filtering the returned search collection.

Would anyone be willing to give me a push in the right direction?

Ooooook! I figured it out.

Updated gist: https://gist.github.com/seanwash/65b39a4491d48f596ebf

I was on the right track. I made filter_by_timeframe a class method since it was being used on a purchase collection (which inherits from Purchase model). The problem I then ran into was an ambiguous pg error:

PG::AmbiguousColumn: ERROR:  column reference "created_at" is ambiguous
LINE 4:         OR lower(name) LIKE '%sean%') AND (created_at >= '20...
                                                   ^
: SELECT  "purchases".* FROM "purchases" INNER JOIN "users" ON "users"."id" = "purchases"."user_id" INNER JOIN "purchase_icon_sets" ON "purchase_icon_sets"."purchase_id" = "purchases"."id" INNER JOIN "icon_sets" ON "icon_sets"."id" = "purchase_icon_sets"."icon_set_id" WHERE (lower(first_name) LIKE '%sean%'
        OR lower(last_name) LIKE '%sean%'
        OR lower(email) LIKE '%sean%'
        OR lower(name) LIKE '%sean%') AND (created_at >= '2015-02-23 00:00:00.000000')  ORDER BY created_at DESC LIMIT 15 OFFSET 0

This was happening because now it didn’t know which model to query for created_at since a join was used. I fixed that by specifying the table name for created at.

Works like a charm! Again, if anyone sees anything that can be improved, please please please let me know!

I made a few comments on the gist. Let me know here if you don’t understand them.

@benorenstein you’re totally right. I actually just watched the method extraction video yesterday. I’m traveling today but I’ll refactor these methods and post an updated gist.

1 Like