Scoping Searches with MetaSearch

Comments

Earlier this month, I released new gems of MetaSearch and MetaWhere. These gems were important personal milestones for me, because with the release of Rails 3 beta 4 and Arel 0.4.0, I was finally able to make a gem release of the work I'd been putting in on GitHub the past few months. I gave a few summary release notes, and then all fell silent on this blog. Part of this is because I've been busy at the office, working on a new iPhone app for a client of ours. Starting tonight, and in preparation for Rails 3 final, I'm going to cover some of the features in more detail. First up: scoping searches.

Why scope searches?

While the simplest (and probably most common) use case for MetaSearch is a simple Model.search(params[:search]) in an admin form, there are plenty of cases in which your general user base should be able to search your data, too. The difference between Joe User and an admin, however, is that Joe probably shouldn't be able to search every record in your database.

Well, duh. So how do I do it?

I'm glad you asked! :)

So, let's say you have a bunch of Projects in your database, and you've already set up a scope to limit visibility. Maybe your scope looks something like this, assuming you're using MetaWhere -- you are using MetaWhere, right?

    scope :visible_to_user,
          lambda {|user| where(:user_id.eq % user.id | :public.eq % true)}

You're also probably using something like José Valim's excellent Devise for authentication, so you'll have a current_user method. Now it's just a matter of filtering your results to projects visible to that user when they do a search.

Prior to 0.5.0, MetaSearch always started searches with a blank slate, which meant that if you wanted to further scope a search, you had to do so by accessing the underlying ActiveRecord::Relation object, like so:

Prior to 0.5.0 (don't use now!):

    @search = Project.search(params[:search])
    @projects = @search.relation.visible_to_user(current_user)

That's not so bad, but it's not very intuitive, either. We can do better. And so we shall. As of MetaSearch 0.5.0:

The new hotness:

    @search = Project.visible_to_user(current_user).search(params[:search])
    @projects = @search # Or maybe @search.paginate(...)

Now, we're doing what should come naturally -- scoping the search before we ever hand it off to MetaSearch to begin with. It's that simple!

comments powered by Disqus