Dashboard namespace - is it a good idea to have Dashboard::PostsController and PostsController?

I have different Rails applications that always end up with the same problem…

You have some controllers, let’s say UsersController or PostsController, that have, in the same file:

  • methods reserved to the authenticated user and displayed in a dashboard layout (e.g. edit)
  • methods that are public to everyone (e.g. show to see a public user profile or a public post)

You end up using before_action (and layout) with except: and only: at the top of the controller. But that doesn’t seem a clean solution.

Some rules are applied to a the “dashboard” group and others are applied to the “public pages” group.

What do you recommend?

I was thinking about creating a new dashboard namespace, so that I have a Dashboard::PostsController and a PostsController … but if you do this you end up with route helpers like new_dashboard_post_path, edit_dashboard_post_path which don’t sound correct.

2 Likes

I’m usually doing as follow:

controller: class Dashboard::Post::CommentsController < ApplicationController

model: module Posts class Comment < ApplicationRecord …

routes: scope module: ‘dashboard’ do
resources :posts do
resources :comments, module: :post … end end end

and end route will be post_comments_path / post_comment_path which is okay.

Yes, the problem with your “scope” approach is that you may end up with name collisions if you have the same controllers in a “admin” and “public” version.

I made some research and namespace :dashboard or namespace :admin are the correct / most common solutions.

However I find it really confusing that Rails generates route helpers like new_dashboard_post_path and edit_dashboard_post_path.

Ideally, the correct naming for a namespace should be dashboard_new_post_path and dashboard_edit_post_path.

Take another example.

Let’s say that you create a namespace :moderator

  • edit_moderator_post_path ← actual, but doesn’t sound correct (you are not editing a moderator post! it’s a moderator that is editing a user post)
  • moderator_edit_post_path ← expected, this would be the correct name for a namespace (but I don’t see how to generate this with Rails, probably not possible)

This sounds like an authentication issue and I’m not sure if multiple controllers is the right approach. Why can’t you wrap your more sensitive actions in authentication checks?

Just in case it helps, most of the time you don’t need to use helpers. Every link_to, redirect_to, as well as a more generic url_for, polymorphic_url/polymorphic_path support the array argument. For example,

link_to 'edit', [:moderator, @post]
link_to 'new', [:moderator, Post]
2 Likes

Usually I have used before_action with only and except, but it’s easy to forget something and introduce possible security issues…

Now I have tried with a DashboardController, which is parent to all controllers in the namespace, and it’s much better IMHO. You have only one place to define layout, auth, etc.

If it works, great! Authorization rules like this should probably be enforced in your specs to make sure you can’t forget - having them separated into controllers doesn’t necessarily stop someone for forgetting to wrap the actions in authenticated logic. However, your controllers that house authenticated actions could probably inherit from an AuthorizedController class or something that ensures the actions are safe.

Have you ever looked into using an authorization gems like pundit? It isolates auth rules but you still have to explicitly declare the authorization in the action itself. Might be easier to track whether things are properly aurthorized that way.