Ruby on Rails RESTful controller function order - ruby-on-rails

I'm pretty new to rails and have been going through the process of building a REST service. In the rails guide it seems pretty specific when they tell you where in the controller class to add their functions: create after new, show before new, etc. I guess I was just curious if there is some convention that most people use for ordering (when I rake routes the order is: index, create, new, edit, show, update, destroy). Not that its a big deal as long as your project is consistent, but is there a "conventional order" that people use? If not, I guess we could all argue about who's order is better.
Thanks!

The order of controller actions isn't really important at all, but I generally follow the same convention that Rails uses in it's own scaffolded controllers.
This way, I can easily scan to the controller action I'm looking for when I open a controller file.
Index, Show, New, Edit, Create, Update, Destroy
I think this order makes sense, as index and show are both concerned with "Showing" or "Reading" data, a primary concern in a web app.
Then new and edit, and create are concerned with "Creating", so they should be grouped together.
After create is update, which are usually very similar.
Then there's destroy, which is usually very simple and the only action of it's kind.
When adding custom actions to a controller, I keep them near the action they are most like, in terms of interactions.
If I have a method that is to display a subset or collection of things, I'll put it under index. If I have actions to upvote or downvote things, I think those fit nicely under update, since they are updating some part of the record.

Totally a personal decision but I do have a way that I set up my controllers:
def index end
def show end
def new end
def create end
def edit end
def update end
def destroy end
# non-restful endpoints/actions
For me, I like new/create and edit/update together since they, essentially, fire one after the other (when you are on the edit view, you're typically going to update the record, etc.).
Ultimately, I think having a system that works for you that you can follow and stay with is most important.

Related

What is a good naming convention for Rails custom controller actions regarding formulation (noun vs verb)?

When defining new actions in controllers I often find myself asking how should I formulate the name of the action correctly. Rails default CRUD actions all seem to follow the pattern of verb (new, create, edit, update, destroy, index) but is it a bad habit to use a noun? For ex. payment_history?
I found a lot of information describing the naming conventions for different files and classes and regarding the proper syntax but none about controller#actions from formulation part.
EDIT: I am asking about custom-defined actions not renaming the Rails default CRUD actions.
In my opinion, important thing about choosing name of the action should not be based on whether it is a noun or a verb, the name of the action should describe the behavior of the action itself, whether it calculates/gets/loads/renders/etc something. So that, when another person (or you after a long time) reads the code, he/she should be able to easily understand what is this action used for and what is expected result from this action.
Otherwise you could just name it is as * whatever * since ruby doesn't prohibit you to do so.
As example we can take a look at payment_history and list_payment_history. If I am reading the code and see action named list_payment_history, I understand that it lists the history, even without looking at the code I understand the purpose of the action. However if I see payment_history, I can only understand that it has something to do with history, not the exact meaning, does it show history, or may be sort history, archive history... no concrete understanding towards the purpose of the action.
Assuming you're following the conventional RESTful methodology, it is going to be easiest to follow the convention of index, show, new/create, edit/update and destroy. That is, unless you have a well-grounded reason not to, but then you ought to be able to justify to yourself and possible other developers why the default action names are not sufficient.
Using the default method names, you get a lot of the routing etc. stuff "for free", as Rails assumes you're following the convention. Also, do note that things that might not immediately sound like "resources" can often easily be modeled as such, e.g. your example "payment_history" may well be a subresource of another resource (a User?), in which case you'd have a singular nested route such as GET /users/{user_id}/payment_history. This route would then call PaymentHistoryController#show, as demonstrated in the Rails guide section on singular resources.
I don't know that it matters so much, though in general I think you're looking for a verb. Your models are typically nouns, and controllers define actions.
Controllers In rails acoording to my reading and experience
Controller class names use CamelCase and have Controller as a suffix. The Controller suffix is always singular. The name of the resource is usually plural.
Controller actions use snake_case and usually match the standard route names Rails defines (index, show, new, create, edit, update, delete).
Controller files go in app/controllers/#{resource_name}_controller.rb.
Example:
# app/controllers/bigfoot_sightings_controller.rb
BigfootSightingsController < ApplicationController
def index
# ...
end
def show
# ...
end
# etc
end
# app/controllers/profiles_controller.rb
ProfilesController < ApplicationController
def show
# ...
end
# etc
end

Rails global variable

Im using bootstrap & rails and have a user model and post model..users create posts (collections)..
with bootstrap in the navbar i want the user to be able to click a dropdown which displays the name's of their posts..i did this on one controller with a private method and a before_action but i don't want to do this for all the controllers and it didn't work for the application controller...
is there a better way to do this??
I was doing this
def list
#user = User.find_by_username(params[:id])
#collections = #user.collections
end
and a
before_action :list
at the top of the controller
What's the most semantic way to accomplish this??
If you could move both to your application controller, then it would be available to any controller. More generally, I'm not sure if this is the best approach to solve your problem.
These tips might also be useful.
Are you using devise? Or some other authentication plugin? If so you're likely going to have a current_user helper. This would allow you to simply do #collections = current_user.collections
To the extent possible, I recommend using more descriptive names for your actions and parameters. def fetch_list_collections might be a better name or instead of passing a param named id, perhaps your param should be named username. These naming conventions become extremely important both for others who might look at your code as well as for yourself if you return to it and are trying to remember what you wrote N months ago.
Your list action is generating a N+1 queries. Meaning that you're hitting the database multiple times when you should do so just once. See the rails guide on this. You might also look at ways to avoid this w/ devise. Devise is pretty well documented and I'll bet there is something in the wiki discussing this.
You may want to consider limiting when you call this action - at a minimum - a post request to an update action? What about before they've logged in? current_user might be nil and you'd have an error attempting to call a collections method on nil.
Take your time learning this stuff. You don't have to learn it all at once, but I thought the above might be helpful.
I got it to work with this in the application controller
before_action :list
private
def list
#collections = current_user.collections
end
thanks #arieljuod

Ruby on Rails Controller methods separately?

Just to be educated I wanted to know if it is a good practice to have one controller method for both GET and POST actions, e.g def signup ... end, which would display a form and if request.post? is true - then perform all the business-logic and so on. Is it any good approach, or should I have these methods being separated from each other ?
Thanks in advice!
I think it'll be much better to define a separate action for the post request. You can obviously get it done within the same action, but if you're going to write a big if..else block in sign_up action you may as well use another action. You could call it create if you're short of names :P . It makes the code more logical and readable.
There is little difference in code organisation either way.
With separate methods, it looks like:
def signup_create
# create here
end
def signup_new
# render here
end
With the same method, it looks like:
def signup
if request.post?
# create here
else
# render here
end
end
It looks like they are both reasonably well organised. Choose what your prefer. If they are the default CRUD methods, separate methods are nice, given that there are separate names thought up already (eg. new vs create, edit vs update).
If they are not CRUD, or extra forms on the page, and you can only think of one name for it (like signup), feel free to overload the name and use the same method.
i think that separate actions for different requests are better if u are using(or going to use) method based authorization (eg cancan).

Trash implementation in rails app

In my app I'm trying to implement trash for some objects, i.e. there will be column "trashed" and it'll set to date, when the object was trashed. Trash also has an index page, where users can restore objects - set "trashed" to nil.
I found examples of models with method trash!, that set trashed to date and it was implemented with Concerns. But I don't really understand how to implement controllers with action to_trash? Is there any way to use Concerns with controllers too or every controller should have it's own action and route for calling it?
Now I implemented it with controller Trash, that have action move_to_trash and every controller use this action, but I have to add get params trashable_id and trashable_type to do this. Is it a good way to do things?
I think the simplest implementation could be to add to your routes.rb file the following:
match ':controller/:id/trash', :action => :trash
This will allow you to use the action trash on every controller. Have a look at the Routing Rails Guide for more examples.
A simple implementation is the following (taking the model Report as example). I don't use Concern here:
class ReportsController < ApplicationController
def trash
#report = Report.find(params[:id])
<Do the trashing of report here, you know that already.>
# Decide what to do after having called #trash
respond_to do |format|
format.html { redirect_to(reports_url) }
end
end
end
If you have only some controllers that should allow the action, it is perhaps easier to add special routes rules for each controller, instead of adding it to every one. And if you want to go a step beyond, you may implement the trash action in a mixin, and mix it in the controller you want to have it in (and no, I don't will implement that, too).

RESTful membership

I am currentlly trying to design a RESTful MembershipsController. The controller action update is used only for promoting, banning, approving,... members. To invoke the update action the URL must contain a Parameter called type with the appropriate value.
I am not too sure if that is really RESTful design. Should I rather introduce sepearate actions for promoting,... members?
class MembershipsController < ApplicationController
def update
#membership= Membership.find params[:id]
if Membership.aasm_events.keys.include?(params[:type].to_sym) #[:ban, :promote,...]
#membership.send("#{params[:type]}!")
render :partial => 'update_membership'
end
end
end
Neither. The only "actions" a controller should handle are GET, PUT, POST, DELETE (+other http verbs). I realize posting this on a question tagged with "rails" is heresy but today I don't care.
One RESTful way to do this is to create new "processing resources" for each of these operations and POST the member to that resource to invoke the action.
When I say create a new resource, you can interpret that to mean, create a new controller.
To me this is one of the cases when you just shouldn't pull your hair out in efforts to adhere to REST conventions. Your model doesn't seem to fit in with the traditional CRUD concept, and the RESTful principle of differentiating actions via HTTP verbs doesn't seem to belong here too.
If I were you, I would split that action into separate actions for what you need to do with your memberships (trying to stay as DRY as possible). That would make the controller code more readable. And by creating some routes I would also make the view code cleaner (promote_membership_path, etc.). But that's just me :), so see what fits most for you.
EDIT:
here is an article which explains my point of view a bit: http://www.therailsway.com/2009/6/22/taking-things-too-far-rest
Well, there is more than one way to do things. The questions you should be asking yourself, is how many states are there? How often do new states get added? Etc.
If there wouldn't be that many states, I would create separate actions + a before filter for the find, but I think this is more of a personal preference. If you really want to keep it short, you can put each method on one line. So:
class MembershipsController < ApplicationController
before_filter :find_membership
def ban; #membership.ban!; render :partial => 'update_membership' end
def promote; #membership.promote!; render :partial => 'update_membership' end
protected
def find_membership
#membership = Membership.find(params[:id)
end
end
To answer your question whether it is RESTful: yes, your update method is perfectly RESTful, but remember that a PUT should be idempotent. So if I execute the same method twice, is the result the same? i.e. what happens if I ban a user and ban him again?

Resources