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.

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](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](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?

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

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.

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.

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...

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.

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.