One Controller Action or Two for Ruby on Rails pages - ruby-on-rails

I currently have one model, one controller with one action to list all the items in the model.
What I need to do is display different data from the model in two separate views. Is there a way I can use one controller action to display different views based on params, or should I create another action?
The reason why I hesitate to create another action is because I'll have to essentially duplicate all the routing I setup for the previous action.
Thanks for any ideas.

I'm not entirely sure that you've provided enough information to give what could be considered a 'good' answer, but if I'm understanding you correctly, this should be possible.
For example, couldn't you do something like this?
def show
#my_objects = MyObject.all
if params[:full_view]
render :action => 'show_full_fiew' and return
end
# if you get here, it will render the 'show' action
end
Let me know if that helps. If you could give some more information, I might be able to clean up this example to be a bit more informative.

You don't mention if you're using resource routes or not. If so, I'd just add a new option to your routes.
map.resources :products, :collection => { :some_great_name => :get }
You really shouldn't worry about adding views or new actions to your controller. An action should usually only have a few lines of code. If your controller actions start to grow in complexity you should think about moving that logic into your model.

Related

Naming convention for rails

So this might be a silly question, but I need to create a new page.
I currently have a controller called jobs, that let's you create a job. However what I want is for there to be a step 2 of the part of creating a job.
Should I create a new controller, and create an index page there, or should I create a page say called part2.html.erb and in the controller create the def part2?
Which leads me into the question is it okay to create names for pages that are not index, show, new, edit and if you need a new page like that create a new controller for it. Or would it be ok to call it things like part2 f.ex. What's the best practice?
It's perfectly fine for you to define controller actions however you like. It's just in your best interest to follow CRUD (create, read, update, delete) 95% of the time.
Personally, I have a fallback in my routes file which sends any "unknown" request to the Pages controller. EG..
# routes.rb
match ':action', :via => :get, :controller => 'pages'
This would work for mysite.com/privacy-policy, mysite.com/contact-us.. whatever
With regards to creating a multi-page form, check this out
http://railscasts.com/episodes/217-multistep-forms

How should I handle triggering an "action method" through a RESTful Controller?

I am trying to keep my controllers nice a RESTful. One thing I keep running into is the need for a button or link on the site to trigger a specific event on a model. For example:
#user.ban!
Currently, I either make a custom named route on the users controller or if it's a more complex set of related actions, I create a new controller that acts on the same model as another "traditionally named" controller.
What is the best approach in this type of situation? What factors weigh into the decision?
In your routes you would typically have a resources declaration looking something like this
resources :users
The best way to add a restfull route to this is to define a ban method in the users controller and add a member route to the users route so your route ends up looking like this
resources :users do
member do
post :ban, :pay, :whatever
end
end
Use a memeber route for form post put actions, i.e. when using button_to or form_for (plus others) view helpers. Use collections for get requests (i.e. links)
Alternatively you could use <%= button_to 'Ban', #user %> then in the update action for the users controller check the commit params for the text ban and act accordingly
Actually I use this myself occasionally like so
if params[:commit] == 'Ban'
# do something like calling a ban method setting a flash notice or alert and redirecting
else
normal controller flow
end
Better still. Use i18n to display the text on the button and check the same i18n value against the commit param thereby leaving you free to change the text text on the button by updating the i18n yml file without breaking your controller code
First off, what jamesw says is good. There are lots of details here...
http://guides.rubyonrails.org/routing.html#non-resourceful-routes
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
... and I actually go with that for whatever unconventional routes I need. About the "factors that weigh into this decision," though... I would first ask myself if this eccentric action is absolutely needed, because more often than not Rails' "convention over configuration" policy comes in. From experience, I find that it's pretty rare for me to need atypical actions. I guess if you can justify it, though, don't feel guilty and go with it.
I have rarely ever had to make a whole 'nother controller, though.

Rails way of constructing & redirecting to an url with post parameters of a form

I would like to do that's the best way of actually accomplishing the
following on Rails.
I have a "Booking Form" with 5 fields (Property, Amount of Children,
Amount of Adults and 2 Dates - Departure and Arrival) based on these
fields, I need to construct an URL and redirect the user to this url.
Now, I have 2 questions.
1) How i catch the POST parameters in the controller, because I'm
mapping the form to an action like this:
<% form_tag(:action => "booking") do %>
and routing it to a controller action like this: (Pages Controller,
Booking Action)
match 'pages/booking' => 'pages#booking'
2) Is this the Rails way of actually accomplishing such thing?
I did it this way in PHP in the past, but now I have the need of
actually doing it in Rails, could you Rails Gurus inspire me ?
To access parameters in the controller, even ones submitted in a POST body, use the params hash. Eg: params[:form_field]
To redirect to another URL using a controller, use redirect_to. You can certainly use the values in params to construct a URL and pass it to redirect_to.
If you're using resourceful routes, which is the best way to go about such things, you would route things through the traditional approach:
resources :bookings
Then you'd post the form to bookings_path and it would all work out, as that's BookingsController#create. It's always better to have a strong correlation between model and controller where possible.
The resources definition in routes.rb helps you by creating all the default RESTful actions which you can build off of. If you really need a custom route, you can always rename it using the :as option, or route it independently.
If you go about creating your own arbitrary routes, such as /pages/booking you're going to create quite a mess that someone else will have to maintain. Quite often that someone else is you in the future.

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?

Polymorphic Routes in Rails - in views

I have Comment as a polymorphic model.
It is attached to Post, Review, etc.
I also have an action in CommentsController, called test.
I have my routes setup, so test_post_comment_path works (to call the test action in the CommentsController).
The problem is, in my partial view, I want that route to be able to change, based on the current action, ie. it is test_post_comment_path when on a Post and test_review_comment_path when on a Review.
The correct way to do this is with polymorphic_url...
Just use two different paths?
What I mean is: you don't want to put so much logic inside routes.
If routes try to do something more than routing, the first time somethings goes wrong you'll be in serious trouble.
In your partial view, the logic to create specific links or other html comment stuff should go in a helper.
Something like this:
(in your partial view)
#commentable.each |commentable|
test_#{commentable.class.to_s.downcase}_comment_path
end
if it is 'post' then it will generate 'test_post_comment_path', if it is review, it will generate test_review_comment_path
I decided to just use an if statement in the view, based on if the current action was present, such as if #post or if #review

Resources