Easy parametric query building in Rails.
Simply add it to your Gemfile.
gem 'scopable'
And update your Gems.
$ bundle update
Please note that as of version 2.0 the API has drastically changed. If you're already using version 1.x and don't want to update your application right now, you should stick with it:
gem 'scopable', '~> 1.0'
Scopable is useful when you need to build one or more queries based on incoming parameters in the request. Very much like has_scope except it's decoupled from the controller, making it easier to test and much more flexible.
Say you have a model and a controller for your blog. Something like this:
└── app
├── models
└── post.rb
└── controllers
└── posts_controller.rb
First let's create a new directory named scopes
along with models
and controllers
. There you create a file called post_scope.rb
, and inside it you define a class that inherits from Scopable
.
class PostScope < Scopable
model Post
scope :search do
where('title LIKE ?', value)
end
scope :published_on do
where(published_at: value.to_time)
end
end
Finally, in PostsController
you use PostScope.resolve
to conditionally resolve the scopes based on given parameters.
class PostsController < ApplicationController
def index
@posts = PostScope.resolve(scope_params)
end
private
def scope_params
params.permit(:search, :published_on).to_h
end
end
Now when any combination of the parameters search
and published_on
are present, their respective conditions are going to be applied on the relation. i.e. If your request path looks like this:
/?search=bananas&published_on=2007-07-19
@posts
will look like this:
Post.where('title LIKE ?', 'bananas').where(published_on: '2007-07-19 00:00:00 +0000')
You can also pass some options when you're defining scopes for more advanced use cases. Read on.
Key | Description |
---|---|
:param |
Name of the parameter that activates the scope. |
:default |
Default value for the scope in case the parameter is missing. |
:value |
Force a value to the scope regardless of the request parameters. |
:required |
Calls #none on the model if parameter is absent (blank or nil) and there's no default value set. |
:if |
... |
:unless |
... |
&block |
Block will be executed in the context of the relation plus two local methods value and params . |
If you'd like to contribute to the project, in any form, you're most welcome, but please bear in mind that as it is with any open-source software your suggestions are subject to the discretion of the project maintainers, and what you see as an issue, someone else may see as a feature.
We encourage you to:
- Open a new issue with suggestions, concerns, or problems you may have.
- Chip in existing discussions and present your opinion on the subject.
- Send pull-requests with test covered bug fixes or new features.
- Send pull-requests with new tests you miss in the suite.
Remember to:
- Be respectful.
- Use proper grammar in discussions and in commit messages.
- Follow the established coding style.
- Explain why you're making the changes in a pull-request.
The MIT License © 2013 Arthur Corenzan