So I'm running Rails 4, just made a barebones application and a User model with Devise. I also ran a migration to add a name attribute to the User model. I also generated a Users controller, as I want to be able to have a Users index page, where all Users are listed. If I specify resources :users in my routes.rb, then what do I do about methods like create in my Users controller, which are already handled by Devise? (I'm aware that this is a rather open-ended question, but some direction would be much appreciated.)
Thanks.
You only need the index action in your user controller.
You can do resources :users, :only => [:index] in your routes.rb file.
Related
I'm still trying to get my head around actions and routes. I more or less understand how to user forms with the build-in controller actions like create, show, etc. What I want to do for a demo app is imitate a school's class schedule, where I have Courses and Students with a has_and_belongs_to_many relationship.
I'm using Mongoid, and I can add students to a course and vice versa using the console, but I can't figure out how to do it with a form. Would adding students to a course even be a controller action, or can I write and call a setter in the model somehow? If a controller action is better, what would the route look like?
If anyone knows of an example that does something similar, I'd love to examine it.
Thanks
It can be a controller action. If adding students to a course is a simple logic, you could add /courses/:course_id/Students/add. This means creating a courses folder, and a students_controller within it, with an add action.
Example (in your routes.rb)
resources :courses, :except => [:destroy] do
resources :students
end
More info: https://gist.github.com/jhjguxin/3074080
Is this what you are looking for?
In my Rails 4 app, an admin can moderate/approve posts, user accounts, and photos. I already have controllers for each of these (PostsController, UsersController, PhotosController) that handle the basic CRUD operations initiated by the user.
Having the update method for each controller seems incorrect and ... dirty. So does creating a single ModerationController with non-RESTful methods for each of the models.
I think I need something like a ModeratePostsController for each of the models, but I'm not sure how that gets scoped (under /admin?) or nested in routes.rb and generated as a controller.
Thoughts?
I was pretty much there.
I ran rails g controller Admin::Posts to create /app/controllers/admin/posts_controller.rb and in the routes file I added:
namespace :admin do
resources :teams
end
My model holds expenses, including user and project references..
class Expense < ActiveRecord::Base
attr_accessible :amount, :expense_date, :description, :project_id, :user_id
belongs_to :project
belongs_to :user
end
The ExpensesController handles basic CRUD operations for the expenses.
I now am needing to build an administrators version of this same page, a new view preferably, which can include the different views of the data, by user, by project, etc, and can also edit data that the user cannot.
My question is: Do a build a second controller to handle the administrative perspective of the data, -- or do I setup conditions inside of every method, to detect the originating view and form, and then conditions to redirect them back to where they belong?
If I do build a second controller, how do I properly setup the form_for so that it knows what controller to go to?
Thanks!
PS - If anyone has any books about how to properly put together a rails app, I feel like I know the pieces ant parts, but I'm getting stuck on the big picture implementation. I learned rails with Michael Hartl's guide, prior to that I was a PHP developer.
IMHO, if security is a big concern for your app then using an admin namespace and separate controllers is the best way to make sure you don't leave any gaps. It's also just simpler and lower stress.
I would have a directory structure like so:
/app/controllers/application_controller.rb
/app/controllers/admin_controller.rb - inherits from application_controller
/app/controllers/expenses_controller.rb - non-admin, inherits from application_controller
/app/controllers/admin/expenses_controller.rb - inherits from admin_controller
Your views would be similarly separated/duplicated:
/app/views/expenses/* - non-admin expenses views
/app/views/admin/expenses/* - admin expenses views
In application_controller you'd put the Devise methods to authenticate_user and CanCan method to check_authorization (which throws an exception if authorization is not checked at some point in the controller action). In admin_controller you have more strict filters to make sure the user is an admin. Then you can get even more fine-grained in the specific controllers and their actions.
Of course each controller only has to define the actions it really needs and you don't have to duplicate views. Maybe the non-admin expenses_controller has index, show, new, create, while the admin one has only edit, update, and destroy. Then in the 'show' view you'd still have code that add links to the 'edit' action if the user is an admin.
Edit - Routes
With the above example, your routes.rb would look something like:
resources :expenses, :only => [:index, :show, :new, :create]
namespace :admin do
resources :expenses, :only => [:edit, :update, :destroy]
end
So you still use expenses_path() for the index and expense_path(foo) for show. A form on the admin page, however, would post to admin_expense_path(#expense).
If you wish to add another Controller I would suggest having common code in a module and importing them in each Controller. Each controller would also have an adequate before filter to check for adequate rights.
But I would prefer having one controller and one set of views since I think it avoids code duplication and/or confusion. Pass the user as a local variable to the view and check for administrator rights when you need to decide the URL for the form_for or whether to hide or show some part.
If the views differ significantly, check for admin rights in the controller and render either the user view or the admin view.
You can even create a special partial for the admin part of the view and decide whether to render it in the view or not, sending the appropriate data in the params or not.
You can use Devise gem for authentication.
You can create somekind of "namespace" for administrative part of your application.
I my opinion, creating another controller depends on how many views and actions your admin will access.
About the doubt about form_for action, it will be managed by your routes and paths that you configure in your form_for params.
Situation: I have a team model, a user model and a teamate model for the users of a team.
Say I want to have a view that contains the information of a team team/show
and that I wish (to simplify the user's experience) to add a list of the users, an add user to team and the possibility to remove a user from that team.
To be perfectly restful, I would need a controller (let's call it Teamates), it would handle the users of a team.
I would have all the CRUD needed.
Is it clean to have the team/show view call the teamates controller for the following actions: adduser, removeuser, listusers.
What I am trying to achieve is less clicks for the users.
In other words, I would like the user to be able to manage the users of a team from the team view instead if requireing him to navigate even further.
I don't think you need a controller for teamates.
And you really should not have adduser/removeuser/etc actions in your team controller!
You could set up your routes like that:
resources :teams do
scope :module => "team_scope" do
resources :users
end
end
Then you would have a UsersController in app/controllers/team_scope/users_controller.rb
To create a new user for a team, you would post to: /team/1-team-a/users and it would hit the create action in the UsersController above.
When you use scope in your routes, it does not change the route helpers like with namespace. The new action would just be accessible via new_team_user_path(#team).
Hum... so yeah, in this case I would have a TeamatesController, and maybe set up my routes like that:
resources :teams do
resources :teamates, :only => [] do
collection do
get :edit
put :update
end
end
end
And then you could edit the associations between a team and its players...
Your form would post the users id to team_teamates_path(team)...
But I'm really not sure it's the best way, I'd have to think about it. This is not really restful as well.
I'm working on a rails app and using a singular resource. However the controller name for the singular resource is plural.
Eg map.resource activity_report expectes the activity_reports_controller.
The explanation given in the rails 3 guide is: "... you might want to use the same controller for a singular route and a plural route..." That is a reasonable explanation, but what is the use case for using the same controller to handle a singular route and a plural route?
In a RESTful Rails application there is usually a mapping of one controller per RESTful resource. For example, let's say we wanted a controller to process user logins (/session) but also to provide a list of users who are currently logged in (/sessions). Logically we could put both of those responsibilities within a SessionsController:
class SessionsController < ApplicationController
# GET /sessions
# Display a list of logged in users
def index
...
end
# GET /session/new
# Display the login form
def new
...
end
# POST /session
# Authenticate a user
def create
...
end
end
An alternative would be to split the functionality for listing logged in users out into a separate administration controller.
You can use it.
class UsersController < Application
end
map.resource :user
map.resources :users
Another situation in which I can imagine using it would be, let's say (and this isn't necessarily the business model you'd want, but stay with me for a moment) you are going to make a site of film reviews, and film information. So, on the one hand you'd have the link to your list of the latest reviews be a plural resource route, something like this:
http://yoursite.com/reviews?count=5
So, in this case, you have a controller for the collection, right? But you're only going to review each movie once. So what if you wanted to provide an easy access to a movie's review?
http://yoursite.com/movies/pirates_of_the_carribean_2/review
Well, there's a nested single resource route, because a movie has_one review, right?