What else to namespace when name spacing controllers? - ruby-on-rails

I plan to make an app with different subdomains for different user types. I will namespace controllers for each of my user types. Now I am thinking what else I need to namespace to make it work right?
If I namespace controllers like this:
app/controllers/student/users_controller.erb
app/controllers/student/...
app/controllers/student/...
Then I guess I also need to namespace Views like this:
app/views/student/homeworks/index.html.erb
app/views/student/homeworks/...
app/views/student/homeworks/...
Should I also namespace helpers and my SessionController where I handle user logins? Also, I don't think I should namespace ApplicationController so how should I handle that problem?
Thanks!

Without seeing the rest of your code it is difficult to know exactly what you are trying to achieve but there is a great Railscasts episode, on sub-domains in Rails, that may help you.
Namespacing your code is not essential to get your code working, although it will help you keep your code organized. Below are some additional things to think about, when working with sub-domains:
Routes
...
match '/' => 'users#show', :contraints => { :subdomain => /.+/ }
...
This example uses a constraint to route all subdomains to the users#show action. You can use this technique to differentiate between subdomains, routing them to appropriate controller actions.
Controller
Once you have set up your routes file to route subdomains correctly, you can retrieve the subdomain in any controller via the request:
def show
#subdomain = request.subdomain
end
This will allow you to add sub-domain specific logic to your application.
View
Linking to views with other subdomains is straight forward, simply pass in the subdomain option to your url method:
root_url(subdomain: 'student')

The easiest way is to use genarators
rails g controller 'student/users' new create etc.
or
rails g controller student::users
When you want to add another controller:
rails g controller student::classes
This creates automatically the necessary structure for the controller and the views.
Then add in your routes:
namespace :student do
resources :users
resources :classes
end
You can use route helpers like new_student_user_path
With a non-namespaced controller you'd typically type form_for #user to create a user, with a namespaced:
<%= form_for [:student, #user] do |f| %>
...
Btw if the difference between the users is just their abilities it's better to use a gem like cancan or declarative_authorization to manage authorization.
If you store different information for each type you could make a single user model with a polymorphic relationship to different profiles.
More info:
How to model different users in Rails
Rails App with 3 different types of Users
......................................
Edit
You can set the layout from application_controller. I guess upon signing in you could store the layout in the cookies or the session hash: session[:layout] = 'student'
layout :set_layout
def set_layout
session[:layout] || 'application'
end
Or if you have a current_user method which gets the user you could check its class and choose the layout.
I strongly advise you to reconsider splitting the user class. Different user models will lead to repeated logic and complicated authentication.

Related

Multiple Layouts in One Ruby on Rails Site

I have a website that is already up and running. I would like to add a new page on my Ruby on rails Website and would like to make the page look completely different.
Different Layout, Different Theme, Everything.
I have created a new scaffold for these pages. but am unsure how to achieve the desired results.
You can create the assets for your theme to make the page look completely different. Rails uses the default app layout at app/views/layouts/application.html.erb
However, you can create another layout with your theme and render the view using:
render layout: "<your-layout-name>"
For different ways to render different layouts, you can also refer to this railscast
Yes, you can do this by passing some params from controller action and checking in application.html.erb
Suppose you have users_controller and home as controller action as your root path
Then in users controller
def home
params.store(:diff_page, true)
end
In application.html.erb
In your application content is the id for main div inside body then
#content{:class => (params[:diff_page] ? "back-black" : "back-gradient")}
back-black and back-gradient both are css classes which you can define different style and page, background image anything you want
You can also call different partial too, based on params
- if params[:diff_page]
= render :partial => 'users/new_page'
- else
= render :partial => "layouts/page"
We do this on one of the sites i help manage: we have two completely different domains, each of which with its own totally unique look and feel, running off the same rails app. The second domain is called "cmw" within our project structure, and is set up as follows.
routes
You can put a condition on routes which looks at the request domain, and only runs that route if the domain matches the condition. So, we put all the cmw routes at the top of the routes file, all with the same condition. Then, underneath, the regular site routes. When we get a request to "cmwdomain.com", it will trigger one of the cmw routes. Requests to "maindomain.com" will fall through all the cmw routes, because they have the condition, which fails for this domain, and hit one of the routes below which are for the main site.
eg
#################### START OF CMW ROUTES: ALL HAVE A CONDITION ON THEM TO DIFFERENTIATE THEM FROM REGULAR ROUTES ###############
cmw = { :host => CMW_HOST_REGEX }
map.resources :licenses, :controller => "cmw/licenses", :conditions => cmw
map.resources :users, :controller => "cmw/users", :conditions => cmw
#REGULAR ROUTES
map.resources :licenses, :controller => "licenses"
map.resources :users, :controller => "users"
controllers
The above system sends all of the cmw requests through to controllers in the app/controllers/cmw folder. Normally, all controllers would extend ApplicationController. In our case, we have a CmwController which extends ApplicationController, and is kind of like the CMW-specific version of ApplicationController. This has its own default layout and various protected methods and helpers which are specific to the cmw site. Then, all the cmw controllers extend CmwController instead of ApplicationController.
views
To match the views to controllers, we have a folder app/views/cmw where all of the different cmw controllers' corresponding view folders live.
This system is nice and clean. The second "cmw" site has its own routes, controllers and views, but accesses the same models and database as the main site: two faces of the same app.

Rails controller and routes configuration for website

I have an application in RAILS, it is composed of a set of API, a basic website, and an admin dashboard.
For the API routing I have no problems, as they belong to a model and a controller and are compliant with the RAILS RESTful pattern (a controller for each model, and a method for each HTTP method).
What I'm not comfortable with is writing routes and controllers for website.
The main website is at / so the default route is root :to => "home#index"and I have
Routes for the website pages which look like
get "home/index"
get "map/index"
get "api/index"
get "cgu/index"
get "legal/index"
Which I think it is not good, as I have a controller per view and I need to define a get for each views.
Now for the dashboard I tried a different approach.
It is at /dashboard, the default route is match "dashboard" => "dashboard#index" and here is few pages as an examples
get "dashboard/index"
get "dashboard/users"
get "dashboard/users_stats"
get "dashboard/routes"
get "dashboard/routes_stats"
get "dashboard/charts"
get "dashboard/financial"
So for the dashboard I have a massive dashboard_controller, which contains a def method for each dashboard pages. IE:
#dashboard/users
def users
#users = User.all
respond_to do |format|
format.html {render :layout => 'dashboard'}
end
end
the controller of the dashboard is at /controller but for views and assets I have put it in /folder/dashboard/
Here is 2 questions:
What is the best way to build the home website and dashboard ? Should I have a controller per page or a global controller where I have a method per pages ? (Which I find very convenient, less code).
How should I organize my routes to avoid to set a get "something/something" for each page ?
Or it is normal with RAILS that I have a route defined for each of my page ? I'm fairly new.
EDIT:
To clarify, the dashboard is built around an existing application with API that follow RESTFul Rails pattern:
resources :users
resources :routes
But the dashboard is not tied to any existing resources, it only do stats about those resources.
If you have custom controller action names, then yes, you'll need to define every route. If you use Restful routes, then you can define them easily as
resources :users
which will automatically create routes for actions: index, show, edit, update, create and destroy.
This might be helpful: http://guides.rubyonrails.org/routing.html
For your dashboard, which probably is bringing together a lot of resources, so they'll probably be custom methods. I'd suggest focusing on building your app by individual resource. Then, once you've defined them all, build your dashboard.
I agree with everything that other people have said here. You should definitely try to be more RESTful and create more routes like this:
resources :users
However, there is usually a controller that is not RESTful (usually called pages or static) that serves pages such as Privacy, About Us, etc, etc. For those routes, I usually do this:
['api', 'privacy', 'us'].each do |p|
get p, :controller => 'pages', :action => p
end
check this guide out if you haven't;
I think you haven't embraced the MVC concept of Rails.
For example, say you have "users". You should have users_controller.rb, users.rb (model), /views/users (view) under the app directory.
users_controller contains the index, show, create, etc default actions and your custom actions like stats
user.rb contains instance/static/helper methods
/views/users/ contains templates that corresponds to actions in the controller.

rails controller action routing

I'm looking to "automatically" generate routes based on actions defined in a controller. resources routing (as far as I know) only automatically generates routes & helpers for http verbs. In this instance I'm serving mostly static pages using rails and have no need for http verbs in my controller.
Specifically:
In a controller I have defined actions which refer to those mostly static pages.
def action
end
In the routes file I have a bunch of
match "/url" => 'controller#action'
I'd like all those matched routes to be generated automatically based on the actions in the controller. Something CONCEPTUALLY along the lines of:
for actions in controller.erb do |action|
'match "/action" => "controller#action"
end
Is this possible? Would I write the code in the routes file directly?
I also have some nested actions to consider... a controller action may be:
def action
def nested_action
end
end
I'd appreciate any thoughts on this matter. Thanks.
What's wrong with the normal /:controller/:action idea?
That won't deal with nested actions, but... I'm having a difficult time understanding why you'd ever want that.
You can do something like this:
controller :controller_name do
get "path/action" => :method_name, :as => :path_action
post "path/save" => :method_name, :as => :path_save
end
That is, you can group different routes within a controller using the method above.

Rails Routing question

I'm not very familiar with routing, but here is my dilemma:
I have a photos controller with the usual show, edit, etc. views. I am trying to build a view to moderate photos. I have a moderate.html.erb view under my photos views. I have also defined moderate method in my photos_controller. If I try to access this view like /photos/moderate I get Couldn't find Photo with ID=moderate.
Am I building this the correct way, or does moderate need to have its own separate controller and view? Seems silly to me for that to be the case. Is this just something I need to configure in my routes?
UPDATE:
I've added this to my routes:
resources :photos do
resources :comments
collection do
get 'moderate'
end
end
Still getting the same Couldn't find Photo with ID=moderate message when I go to /photos/moderate...
UPDATE:
Crap! Just figured out the problem. I had a before_filter running that needed to ignore the moderate action... It's now working fine. Sorry for the trouble.
You can add a further restful action. Take a look at the docs
So you're trying to split out the concern of being able to edit and view photos?
If you wanted to keep your actions RESTful, you could create a "moderate" namespace and put all the actions that require authentication for photos in that namespace.
For instance,
#routes.rb
namespace :moderate do
resources :photos # will create paths like '/moderate/photos/', '/moderate/photos/1'
end
#controllers/moderate/photos_controller.rb
class Moderate::PhotosController < ActionController
before_filter :authorize_moderator!
#your standard restful actions like 'index', 'show', 'edit, 'update' would go in here.
end

1.8.x Ruby on Rails RESTful nested admin page and form_for problems

So I am creating a website that I want to have an admin directory in rails 1.8.x and I'm struggling a bit to get the form_for to link to the right controller. I am trying to be RESTful. What I basically want is an admin page that has a summary of actions which can then administer sub models such as:
/admin (a summary of events)
/admin/sales (edit sales on the site)
/admin/sales/0 (the normal RESTful stuff)
I can't use namespaces since they were introduced in Rails 2.0 (production site that I don't want to mess with updating rails and all that).
Anyway, what I have in the routes.rb is:
map.resource :admin do |admin|
admin.resources :sales
end
I am using the map.resource as a singleton as recommended by another site.
The problem comes in when I try to use the form_for to link to the subresource RESTfully. If i do :
form_for(:sales, #sale)
it never links to the right controller no matter what I try. I have also tried:
form_for [#admin, #sale] do |f|
and that does not work either (I am guessing since admin is a singleton which does not have a model, it's just a placeholder for the admin controller). Am I supposed to add a prefix or something? Or something into the sales controller to specify that it is a subcontroller to admin? Is there an easier way to do this without manually creating a bunch of routes? Thanks for any help.
You can use controller, action and html options something like following.
<%= form_for :sales, :controller=>controllerName, :action=>actionName, :id=>idParameter}, :html=>{:onsubmit=>"someFunction()"} do |f| %>
|
|
|
<% end %>

Resources