How do you pass validation errors across controllers? - ruby-on-rails-3

I'm making a conventional forum in Rails to practice. I have a Topic model and a nested Post model. Topics can have many Posts.
Topics#Show has a list of #topic.posts and then a new Post form.
# Topics#Show
def show
#topic = Topic.find(params[:id])
#post = #topic.posts.new
end
Submitting a new post sends it to Posts#Create
# Posts#Create
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.new(params[:post])
#post.user = current_user
if #post.save
redirect_to #topic, :notice => "Successfully created post."
else
render :action => 'new' # <-- Unsure what to do here
end
end
If the Post fails to save, I want it to render Topics#Show and display the validation errors there.
From what I understand, params don't persist through a redirect_to because a 302 redirect starts a new request.

You should render the topics/show view. So instead of
render :action => 'new' # <-- Unsure what to do here
Do:
render :template => 'topics/show'

Use render :template => "topics/show" and be sure to set up the #topic variable identically to how you do it in the TopicsController#show action. You will not be able to call this show method from the PostsController though.

Related

respond_with do not redirect to index.html.erb

I need help with the responder respond_with, 'cause when I create a new post (in this case) It doesn't redirect to the location specified. What can be?. This is the piece of my code that creates a new post but It's be redirected to create.html.erb and not the index.html.erb that I specified.
def create
#post = Post.create(params[:post])
respond_with(#post, :status => :created, :location => posts_url)
end
try to use "redirect_to" (from ACIIcasts - Controllers in Rails 3):
redirect_to #result, :notice => "Successfully converted original data."
If you are not confortable with the solution i found a workaround in a similar post: link
def convert
#result = Result.find(params[:id])
#result.convert_original_data
success = #result.save
respond_with(#result) do |format|
format.html {redirect_to result_path(#result) } if success
end
end
You don't need to supply location. It will do it automagically for you.
All you need to do is...
respond_with #post
It will set the correct status and redirect you to the posts_url.

How to render validation errors on the page that submitted the form?

I've got a comments form in the article/show page. In this page, it displays the article and has a comments form.
When I submit a comment that has validation errors, I need it to go back to the article/show page, and display the errors there.
Should I change render :action => 'new' to something else?
In the Comment controller, I tried:
def create
...
if #comment.save?
redirect_to article_path(#comment.article), :notice => "Posted comment!"
else
# render :action => 'new'
render 'articles/show"
end
end
But this will complain, since the app won't know which article to show based on the ID.
EDIT: I found this solution. The approach would be to use a session to pass the errors instead. Is this the right way to go with this?
Try this
def create
...
if #comment.save?
redirect_to article_path(#comment.article), :notice => "Posted comment!"
else
# render :action => 'new'
#article = #comment.article
render 'articles/show"
end
end`
So fix your routing so the app does know what article to show based on the ID.

problem with RESTful forms in Rails 3

okay, so basically, I have a normal form for my model:
= form_for #operator do |f|
blah blah blah
In my operators controller, i have this:
def new
#operator = Operator.new
#operator.build_user
respond_to do |format|
format.html {}
end
end
def create
#user = User.create(params[:operator].delete(:user))
#user.update_attributes(:login => #user.email)
#operator = Operator.new(params[:operator].merge(:user => #user))
respond_to do |format|
if #operator.save
format.html {redirect_to new_operator_aircraft_path(#operator)}
else
format.html { render :action => "new", :error => #operator.errors }
end
end
end
very basic stuff. I have some validates_presence_of stuff in my model so naturally when I submit my form, it should show me that I have errors(and keep the fields I have filled up)
Right so far? yeah. The problem is, it seems I am posting to /operators and that's what renders. I seem to have forgotten about what happens in Rails2.3+ but shouldn't I be redirected to /operators/new again? or was that the intended behavior all along?
Here's what I think you are asking:
After I submit a form with errors, why does the URL
read "/operators" rather than
"/operators/new".
Thanks to resourceful routing, when submitting a form via POST to "/operators" the create action is called on the OperatorsController. If you encounter errors when saving your operator, you've instructed the controller to render the new action within the same request.
render :action => "new", :error => #operator.errors
This means a redirect is not occurring and therefore the URL remains "/operators".
If a redirect were to occur, you would lose all the state information of the #operator object in the current request, including the errors you encountered as well as the form values you just submitted.
In other words, working as intended.

Rails3 and Respond_with problem

I have an application, on which I have two user interfaces.
The first one is for normal users and the second one is for iphone users.
Everything was working fine until i refactored my code within controller to use the respond_with declarative instead of respond_to.
The application is still working for the html interface(:format => :html) but not on the iphone interface(:format => :iphone).
On the iphone, when I do the following action (:index, :new, :edit, :show) it works.
But when i do (:create, :update, :destroy), I get errors saying the template is not found(create.iphone.haml for example).
On my controller I have
respond_to :html, :iphone
And then for example, the edit and the update action
def edit
#refund = Refund.find(params[:id])
respond_with(#refund)
end
def update
#refund = Refund.find(params[:id])
if #refund.update_attributes(params[:refund])
flash[:notice] = 'Refund was successfully updated.'
end
respond_with(#refund, :location => project_refunds_path(#project))
end
In fact, I would like the :iphone format is handle as :html is ... and not by calling the to_format method as it is specified into the doc.
Solved it by myself.
Just need to add this to an initializer file :
ActionController::Responder.class_eval do
alias :to_iphone :to_html
end
What if you do:
respond_with(#refund, :location => project_refunds_path(#project)) do |format|
format.iphone { whatever you had here before refactoring }
end

How do I make a route to a custom controller action in Rails 3?

I'm new to Rails, and a bit confused about routes:
I have a Devices controller:
#devices_controllers.rb
class DevicesController < ApplicationController
def index
#devices = Device.all
end
def show
#device = Device.find(params[:id])
end
def new
#device = Device.new
end
def create
#device = Device.new(params[:device])
if #device.save
flash[:notice] = "Successfully created device."
redirect_to #device
else
render :action => 'new'
end
end
def edit
#device = Device.find(params[:id])
end
def update
#device = Device.find(params[:id])
if #device.update_attributes(params[:device])
flash[:notice] = "Successfully updated device."
redirect_to #device
else
render :action => 'edit'
end
end
def destroy
#device = Device.find(params[:id])
#device.destroy
flash[:notice] = "Successfully destroyed device."
redirect_to devices_url
end
def custom_action
"Success"
end
I'd like to access the "custom_action" action via a url like this:
http://foo.bar/devices/custom_action
I've added this line to my routes.rb file:
match 'devices/custom_action' => 'devices#custom_action'
However, when I try the URL in the browser, I get this error:
ActiveRecord::RecordNotFound in DevicesController#show
Couldn't find Device with ID=custom_action
It seems to be going to #show action instead of #custom_action. If a user id is not supplied, and I go to http://foo.bar/devices/custom_action, I'd like it to go #custom_action.
I've read Rails Routing from the Outside, but still can't still seem to figure out the problem.
I think the problem may be because of the order in which you have defined your routes.
I suspect you have resources :devices in your routes.rb. In addition, I suspect you have defined your custom route after this. If you type rake routes into your console/terminal, you will see that there is already a route defined for the following pattern:
GET /devices/:id
This route is a product of resources :devices, which is taking precedence over your custom route. Referring back to the Edge Guides, specifically in 1.1. Connecting URLs to Code, it states that the request will be dispatched to the first matching route. So a simple fix would be to define your custom route before resources :devices.