Rails Routes/Controller/Directory Structure design question

I have a design question where I would appreciate a thoughtful
response.

Let’s say you have a simple application (for example’s sake) that has
a User, Company and Theme model. A Company has_one Theme and
has_many Users.

Administrators (a User) can fully manage Companies and Themes - the
whole REST stack, in addition to a few other actions too.
Administrators are expected to do things to Companies and themes that
other user roles cannot do.

We also have a Company role. This role can edit their own Company, as
well as select a Theme from the ones the admin-user added as nice
defaults, or they can just make their own theme.

Now, here we have some non-trivial design choices, and I would like to
know what the best-practice is.

PART 1

In Rails, it makes sense to have
resources :users, :companies, :themes for the administrators and
probably resource :company, :theme, :users for the Company users.

But of course, we run into some naming conflicts here - both singular
and plural - so we might want to try something like
resource :my_company, :my_theme, :my_users to separate them? Or is
there a better solution?

Furthermore, a theme is just a component of a company, so maybe we
want to nest them?

:resource :my_company do
  :resource :theme
  :resources :users
end

This works okay, but it could be confusing as to which UsersController
we are referring to… no? This is really sticky and I would love to
know how to deal with this. Do you have 1 controller, or 2? What do
you name them?

But then I look at the url, and it’s kind of silly:

http://myapp.com/my_company/my_theme/edit

I guess it could be worse.

Company users also might want the list of themes via ajax, so is it
correct for them to call:

http://myapp.com/themes.json

?

Is this how to approach this situation, or is there a better way?

PART 2

Also, what should your directory structure look? Should you have
controllers separated by user role?

/app/controllers/admin/companies_controller.rb
/app/controllers/admin/themes_controller.rb
/app/controllers/admin/users_controller.rb
/app/controllers/company/my_company_controller.rb
/app/controllers/company/theme_controller.rb
/app/controllers/company/users_controller.rb

Or is there better ways to handle this?

I would really appreciate a thoughtful response on this. Thanks!

Oh, I also want to add that Admins will manage Users too, not just
Companies and Themes. So there is a conflict where Companies can
create/edit/delete Users and use/not use the same controller. There is
also potential route conflicts unless you use nested resources.

I also want to add that Admins can do some things to users, but
Company users can do other things. It’s not just a subset - but the
views and actions and forms will be somewhat different.

That is why I am having difficulty figuring out the routes, what the
controllers should be, and what to generalize and what to keep
separate.

On Fri, May 27, 2011 at 7:55 PM, egervari [email protected]
wrote:

other user roles cannot do.
In Rails, it makes sense to have

But then I look at the url, and it’s kind of silly:
?
/app/controllers/admin/users_controller.rb
/app/controllers/company/my_company_controller.rb
/app/controllers/company/theme_controller.rb
/app/controllers/company/users_controller.rb

Or is there better ways to handle this?

Look into namespacing your routes. So you could end up with the
directory
structure above, and have it be clean like:

resources :company
resources :theme
resources :users

namespace :admin
resources :company

end

On Fri, May 27, 2011 at 8:00 PM, egervari [email protected]
wrote:

controllers should be, and what to generalize and what to keep
separate.

That is a challenge and there is no right answer, only what is cleaner.
What
is nice about the namespacing way of going is that you have a more clear
delineation as far as rights for the admin. It might mean you dup some
code
between the controllers. But that is certainly cleaner than having
special
cases in a single controller that sooner or later could become
problematic.

On May 27, 9:02pm, David K. [email protected] wrote:

Administrators are expected to do things to Companies and themes that

want to nest them?

/app/controllers/admin/themes_controller.rb
resources :company
resources :theme
resources :users

namespace :admin
resources :company

end

Interesting… I forgot about namespaces. So you suggest namespacing
the admin, but nest “my_company”?

Also, how is my proposed directory structure? Sound good? Is there a
better way?

How do you deal with form_for’s when the routes are nested?

For example, let’s say you have a Admin::CompaniesController in
your :admin namespace. The model is obviously Company. I get an error
for new forms:

<%= simple_form_for(@company, :url =>

admin_company_path(@company)) do |f| %>

Here’s the error message:

ActionView::Template::Error: No route matches

{:action=>“show”, :controller=>“admin/companies”, :id=>#<Company id:
nil, name: nil, phone_number: nil, address: nil, postal_code: nil,
is_enabled: true, courses_created: 0, province_id: nil, theme_id: nil,
payment_plan_id: nil, created_at: nil, updated_at: nil>}

How can I get rails to play nice? I have no idea why it’s even trying
to use the show action at all…

Try running rake routes and see what you get… then either use what you
have available or modify so you have the route you want.

Well, that was the problem - it’s not about the routes being - it was
about rails doing the wrong thing.

The solution was to put:

[:admin, @company]

And then rails would generate the proper :post and :put routes given
this. It tripped me because there’s no way I would have thought of
this…

I mean, to replace a parameter of a model to an array is just strange
for me. It’s elegant, but you have to know this in advance - it’s
hardly intuitive. Someone would have to tell you or you’d have to look
at the source.

On Fri, May 27, 2011 at 9:11 PM, egervari [email protected]
wrote:

ActionView::Template::Error: No route matches
{:action=>“show”, :controller=>“admin/companies”, :id=>#<Company id:
nil, name: nil, phone_number: nil, address: nil, postal_code: nil,
is_enabled: true, courses_created: 0, province_id: nil, theme_id: nil,
payment_plan_id: nil, created_at: nil, updated_at: nil>}

How can I get rails to play nice? I have no idea why it’s even trying
to use the show action at all…

Try running rake routes and see what you get… then either use what
you
have available or modify so you have the route you want.