Skip to content
Jonathan Chan edited this page Jul 4, 2024 · 8 revisions

This tutorial shows how to use Rails routes constraints with Sorcery gem. Thanks to @anthonator for writing it!

First, define UserConstraint module that will be used for all constraints:

module RouteConstraints::UserConstraint
  def current_user(request)
    User.find_by_id(request.session[:user_id])
  end
end

Then, having that module defined, you can specify specific constraint classes. In these examples, first route will work only if there's no user logged in, the second will work only for logged user who is an admin:

class RouteConstraints::NoUserRequiredConstraint
  include RouteConstraints::UserConstraint

  def matches?(request)
    !current_user(request).present?
  end
end
class RouteConstraints::AdminRequiredConstraint
  include RouteConstraints::UserConstraint

  def matches?(request)
    user = current_user(request)
    user.present? && user.is_admin?
  end
end

Finally, you can add the constraints to the config/routes.rb:

MyApp::Application.routes.draw do

  # other routes …

  root :to => 'admin#dashboard', :constraints => RouteConstraints::AdminRequiredConstraint.new
  root :to => 'home#welcome', :constraints => RouteConstraints::NoUserRequiredConstraint.new, as: nil

end

It should be noted that the constraint current_user is not the same as sorcery'scurrent_user. If you are wrapping a route that already calls sorcery's current_user, you will effectively be doubling the amount of database calls to User.find_by_id(). The constraints methodology would be more useful for wrapping engines or other routes that you do not want to modify the code for. It is more efficient to use the require_login before action as all calls to Sorcery's current_user are cached. Only 1 call to the db is made per request no matter how many times you call current_user.