How to Use auth_object in Ransack for Secure Authorization
Pass an auth_object to Model.ransack() and override ransackable_attributes to selectively expose columns based on user privileges.
Ransack, the popular querying library for Ruby on Rails maintained by activerecord-hackery/ransack, provides a built-in authorization mechanism to prevent users from filtering or sorting by unauthorized database columns. By leveraging the auth_object option, you can enforce fine-grained access control at the model level without cluttering your controllers with authorization logic.
How auth_object Works in the Ransack Pipeline
When you initialize a search with the auth_object parameter, Ransack propagates this value through the entire query-building lifecycle, using it to validate each field against whitelist methods defined on your models.
Capturing the Option in the Search Object
The authorization process begins in lib/ransack/search.rb, where the constructor extracts the auth_object from the options hash and assigns it to the search context:
# lib/ransack/search.rb (line 34)
@context.auth_object = options[:auth_object]
This single assignment stores the authorization context for the duration of the search construction.
Propagating Through the Context
The Ransack::Context class acts as a data holder that carries the auth_object through every phase of query construction. As shown in lib/ransack/context.rb, this object is accessible via a simple attribute accessor:
# lib/ransack/context.rb (line 6)
attr_accessor :auth_object, :search_key
This context object is passed to every node factory, ensuring that authorization checks occur consistently whether you are filtering, sorting, or scoping.
Implementing Authorization Checks
Ransack queries the target model's class methods to determine if a requested field is permissible. These methods all receive the auth_object as their first argument, allowing you to implement conditional logic based on the current user's role or permissions.
Filtering Attributes and Sorts
When Ransack resolves an attribute name, it invokes ransackable_attributes on the parent class, passing the current auth_object. In lib/ransack/nodes/attribute.rb, the validation occurs at line 23:
# lib/ransack/nodes/attribute.rb (line 23)
context.klassify(parent).ransackable_attributes(context.auth_object)
Similarly, sortable columns are validated in lib/ransack/nodes/sort.rb using ransortable_attributes, which by default delegates to ransackable_attributes:
# lib/ransack/nodes/sort.rb (line 29)
context.klassify(parent).ransortable_attributes(context.auth_object)
If the requested field is not returned by these methods, the predicate is silently excluded from the generated SQL.
Restricting Associations and Scopes
The authorization check extends to associations and scopes. In lib/ransack/context.rb (lines 162-171), Ransack validates these against ransackable_associations and ransackable_scopes:
# lib/ransack/context.rb (lines 162-171)
klass.ransackable_attributes(auth_object).any? … ||
klass.ransortable_attributes(auth_object).any? …
klass.ransackable_associations(auth_object).any? …
klass.ransackable_scopes(auth_object).any? …
You can restrict associations and scopes by overriding these methods in your model. The default implementations in lib/ransack/adapters/active_record/base.rb (lines 37-61) return all columns and associations, but you should override them to enforce your security policy:
# lib/ransack/adapters/active_record/base.rb (lines 37-61)
def ransackable_attributes(auth_object = nil) … end
def ransackable_associations(auth_object = nil) … end
def ransortable_attributes(auth_object = nil) … end
def ransackable_scopes(auth_object = nil) … end
Practical Rails Implementation
To implement authorization in a Rails application, compute the appropriate auth_object in your controller and pass it to the Ransack initializer. Then implement the whitelist methods in your models to check this object.
Controller Setup
Create a private method that returns the authorization context, and pass it as the second argument to ransack:
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
@q = Article.ransack(params[:q], auth_object: ransack_auth_object)
@articles = @q.result
end
private
def ransack_auth_object
current_user.admin? ? :admin : nil
end
end
Model Configuration
Override ransackable_attributes to return different column sets based on the auth_object value:
# app/models/article.rb
class Article < ApplicationRecord
def self.ransackable_attributes(auth_object = nil)
base = %w[id title body created_at]
auth_object == :admin ? base + %w[internal_notes status] : base
end
def self.ransackable_associations(auth_object = nil)
%w[comments author]
end
def self.ransackable_scopes(auth_object = nil)
auth_object == :admin ? %w[recent deleted] : %w[recent]
end
end
With this configuration, non-admin users attempting to filter by internal_notes will have those predicates silently ignored, while admins can search all columns.
Summary
- Pass
auth_objectas the second argument toModel.ransack(params, auth_object: value)to propagate authorization context through the query builder. - Implement whitelist methods (
ransackable_attributes,ransackable_associations,ransortable_attributes,ransackable_scopes) in your models to check theauth_objectand return only permitted fields. - Unauthorized fields are silently ignored, preventing SQL injection of restricted columns without raising exceptions.
- The context stores the object at
lib/ransack/search.rbline 34 and validates against it inlib/ransack/context.rbduring predicate resolution.
Frequently Asked Questions
What data type should I pass as auth_object?
You can pass any Ruby object that represents the current authorization context. Common patterns include symbols like :admin, the current_user model instance, or a custom policy object. The Ransack source code treats this as an opaque value that is simply forwarded to your model's whitelist methods.
Why are unauthorized queries silently ignored instead of raising errors?
Ransack follows a permissive design philosophy where unknown or unauthorized attributes are filtered out during the search construction phase. This behavior, implemented in lib/ransack/context.rb, prevents information leakage about which columns exist in your database while maintaining a smooth user experience. If you need strict validation, implement pre-flight checks in your controller before calling Ransack.
Can I use auth_object with Ransack scopes?
Yes. When you define ransackable_scopes in your model, the method receives the auth_object just like the other whitelist methods. You can conditionally expose scopes based on the authorization context, ensuring that powerful query shortcuts are only available to privileged users.
How do I test authorization with auth_object?
In your RSpec or Minitest suite, instantiate the search object directly with different auth_object values and inspect the resulting SQL. For example, Article.ransack({ internal_notes_eq: 'secret' }, auth_object: nil).result.to_sql should not include the internal_notes condition, while passing auth_object: :admin should include it.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →