views:

183

answers:

2

I've been developing the CMS backend for a website for a few weeks now. The idea is to craft everything in the backend first so that it can manage the database and information that will be displayed on the main website.

As of now, I currently have all my code setup in the normal rails MVC structure. So the users admin is /users and videos is /videos.

My plans are to take the code for this and move it to a /admin directory. So the two controllers above would need to be accessed by /admin/users and /admin/videos. I'm not sure how todo the ruote (adding the /admin as a prefix) nor am I sure about how to manage the logic. What I'm thinking of doing is setting up an additional 'middle' controller that somehow gets nested between the ApplicationControler and the targetted controller when the /admin directory is accessed. This way, any additional flags and overloaded methods can be spawned for the /admin section only (I believe I could use a filter too for this).

If that were to work, then the next issue would be separating the views logic (but that would just be renaming folders and so on).

Either I do it that way or I have two rails instances that share the MVC code between them (and I guess the database too), but I fear that would cause lots of duplication errors.

Any ideas as to how I should go about doing this?

Many thanks!

A: 

You can do this without an extra controller, relatively easily in config/routes.rb:

# non-admin routes
# your args could include :only => [:index,:show] for the non-admin routes
# if you wanted these to be read-only
map.resources :users,  ...your args..., :requirements => { :is_admin => false }
map.resources :videos, ...your args..., :requirements => { :is_admin => false }
# admin routes
map.resources :users,  ...your args..., :path_prefix => '/admin', \
    :name_prefix => 'admin_', :requirements => { :is_admin => true }
map.resources :videos, ...your args..., :path_prefix => '/admin', \
    :name_prefix => 'admin_', :requirements => { :is_admin => true }

What :requirements actually does here, because I gave it a constant and not a regex, is just to add params[:is_admin] when accessed via this route. So you can check this value in your controller, and render different views, or you can just check it in the view if the two views are similar. It's important to include the requirement with false on the non-admin versions otherwise people can just use /users/?is_admin=true.

The :name_prefix edits the route names, so you have e.g. admin_video_path(123) as well as video_path(123).

Tested on Rails 2.3.5, other versions may differ. For more about the options available on RESTful routes, see the ActionController::Resources docs.

Chris Boyle
Thank you guys. This is exactly what I needed.
matsko
+2  A: 

If you don't mind having two controllers for each resource, you could have a separate "admin" namespace. I like it this way, since the admin section is completely different from the public one. Admin controllers implement all CRUD actions, whereas the public ones implement only show and index actions.

routes.rb:

map.namespace :admin do |admin|
  admin.resources :users
  admin.resources :videos
end

map.resources :videos, :only => [:index, :show]

Your controllers could be something like:

class VideosController < PublicController; end

class Admin::VideosController < Admin::AdminController; end

class PublicController < ApplicationController
  layout 'public'
  before_filter :load_public_menu
end

class Admin::AdminController < ApplicationController
  layout 'admin'
  before_filter :login_required, :load_admin_menu
end

Namespaced controllers and views have their own subdirectory inside the app/controllers and app/views directories. If you use the form_for helper, you need to modify its parameters:

form_for [:admin, @video] do |f|
Teoulas