Background
My application is using Multi-Tenency With Scopes, which basically means many of my models use default_scope to compare the current_tenant.id to a tenant_id column to determine if the current_user is authorized to access that object.
I'm also using CanCan for authorization.
Question: How do I deep link to a particular object for a user who isn't logged into the application yet?
General Use Case
I want to be able to email a user and say, "This task has been assigned to you. Click here to see the task." Then the user would click a link (e.g., http://myapp.com/task/15) and be taken directly to the task if they are already logged in to the appropriate tenant (that the task belongs to). Or, if they're not logged in, they'd be redirected to a Sign In page with a message that says, "Please log in to access this page."
Examples
First, an example that behaves as I'd expect:
If a user is logged out and goes to http://myapp.com/tasks, then CanCan checks to see if the "Guest" user is authorized to go to Tasks#index. The Guest isn't authorized to do that, so CanCan raises an exception, which I handle by recording the target path and redirecting to a Sign In page with a message to "Please sign in to access this page."
And here's an example that has me stumped:
A user is logged out and clicks a link to http://myapp.com/tasks/15. The user will always get a 404 (not found) error because the first thing Rails does is try to find that particular object. But since the user is logged out (meaning current_tenant isn't defined), and that Task is for tenant_id == 5, Rails can't find the object and raises an exception.
Here's the full debug/stacktrace:
INFO -- : Started GET "/tasks/15" for 127.0.0.1 at 2014-12-14 11:16:59 -0500
INFO -- : Processing by TasksController#show as HTML
INFO -- : Parameters: {"id"=>"15"}
DEBUG -- : Task Load (0.8ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."tenant_id" IS NULL AND "tasks"."id" = $1 LIMIT 1 [["id", 15]]
INFO -- : Completed 404 Not Found in 4ms
FATAL -- :
ActiveRecord::RecordNotFound (Couldn't find Task with 'id'=15 [WHERE "tasks"."tenant_id" IS NULL]):
app/controllers/application_controller.rb:46:in `scope_current_tenant'
And here's the 'scope_current_tenant' method from application_controller:
def scope_current_tenant
Tenant.current_id = current_tenant.id if current_tenant
yield
ensure
Tenant.current_id = nil
end
What I prefer to happen is the same thing that happens when the user tries to access Tasks#index when logged out.
Any ideas how to handle this?
It sounds like you need to verify that the user is logged in before trying to find the task. Do you have a before_action :authenticate_user!
or similar in your TasksController
?