DoubleRenderError after Net::HTTP.post_form - ruby-on-rails

Hi i want to post xml data to server and redirect page according to response.
For this in my controller i have my action and send_xml method.
Ruby Version: 2.0.0-p247
Rails Version: 3.2.17
def new
#sales = current_user.sales.new
respond_with(#sales)
end
def fail
flash[:error] = 'Canceled'
render :new
end
def success
result = send_xml(params)
if result['Response'] == 'Approved'
flash[:success] = 'Approved'
redirect_to(approved_path)
return
else
flash[:error] = 'Failed'
redirect_to(failed_path)
return
end
end
private
def send_xml(params)
request = "DATA=<?xml version=\"1.0\" encoding=\"ISO-8859-9\"?><myData>Foo</myData>"
uri = URI.parse('http://foobar.com')
xml = render xml: request
response = Net::HTTP.post_form(uri, xml)
response = Hash.from_xml(response.body)
response['myResponse']
end
When i try to run this action i get error like:
AbstractController::DoubleRenderError
Render and/or redirect were called multiple times in this action. Please note that you
may only call render OR redirect, and at most once per action. Also note that neither
redirect nor render terminate execution of the action, so if you want to exit an action
after redirecting, you need to do something like "redirect_to(...) and return".
I guess NET::HTTP.post_form method triggers render or redirect and that cause this error.
How can i get rid of this error.
Thanks for help

This happens because you are calling render xml: request in #send_xml which you are calling from #success, therefore you are calling render and redirect which results in the exception (as the message also indicates).

Related

DoubleRenderError in Controller

before_action :set_blacklisted_nfts, only: %i[blacklisted_nfts]
def blacklisted_nfts
if #blacklisted_nft.present?
redirect_to destroy and return
end
end
def destroy
success = false
message = 'Unable to delete NFT!'
if !current_user.admin?
message = 'This action require admin privileges!'
elsif #nft.destroy
success = true
message = 'NFT deleted successfully!'
end
render layout: false, locals: {
type: success ? 'success' : 'error',
message: message,
nft_id: #nft.id
}
end
private
def set_blacklisted_nfts
#blacklisted_nft = BlacklistedNft.create(contract_address: #nft.contract_address, contract_type: #nft.contract_type, token_id: #nft.token_id, chain: #nft.chain)
end
can anyone guide me where is an issue am having this error:
Error: Render and/or redirect were called multiple times in this action. Please note that
you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
Where you have redirect_to destroy that's actually calling the destroy method. You might be trying to redirect to the destroy method, but it's calling it directly.
You can't actually redirect to anything other than another "GET" action, the redirect just responds back to the browser with a URI and the browser just calls a GET on it, you can't have a POST or DELETE or any other http method (aka: http verb).
Probably instead in that condition, you just want to do a #blacklisted_nft.destroy and then redirect_to :back, notice: "Deleted #blacklisted_nft.name" or something.

redirect_to not working in Ruby on Rails

In Rails side, I have two controllers: A_controller and B_controller. And when the client side hits one of the actions in A_controller, it probably gets an exception. And when the exception happens, I would like to have the rails redirects to a new page (under B_controller). So, below is what I did:
class AController < ApplicationController
rescue_from SampleException, :with => :redirect_to_page_b
def redirect_to_page_b
redirect_to "/b/#{#id}" # a URL here
end
end
However, when the browser didn't redirects to the new page and I debugged with the ajax call and noticed that the response is success with status = 200. Why does this happen?
If you do an ajax request, you probably request json or js format. But your redirect_to is response for html format, so it just does nothing.
Depending on what format you request, you can handle the error differently.
If you request js format, you can keep the rescue in your controller and do:
def redirect_to_page_b
respond_to do |format|
format.html { redirect_to "/b/#{#id}" }
format.js { render js: "window.location = '/b/#{#id}'" }
end
end
Requesting a json format, I would remove the rescue block from the controller and let the error to happen. Then I would handle it in the fail block of the ajax call.
Or if you need only to handle specific type of exception, you can still keep the rescue and respond there with such json:
render json: { redirect_link: "/b/#{#id}" }
then in done callback of your ajax call you can check presence of redirect_link in the response, and if it's there, assign it to window.location.

<AbstractController::DoubleRenderError in controller

I'm getting this error, I tried adding a redirect_to() and return to my access_doc_or_redirect() method, but no luck. Any recommendations?
def access_doc_or_redirect(doc_id, msg)
doc = Document.find(params[:id])
if doc.user_access?(current_user)
#document = doc
else
flash[:alert] = msg
redirect_to root_url and return
end
end
def get
access_doc_or_redirect(params[:id], "Sorry, no document view access.")
redirect_to #document.file.url
end
Error
access_doc_or_redirect(params[:id], "Sorry, no document view access" AbstractController::DoubleRenderError: Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
AbstractController::DoubleRenderError: Render and/or redirect were called multiple times in this action.
Error is self descriptive you are calling render or redirect multiple times in your action. Lets look at your methods:
def access_doc_or_redirect(doc_id, msg)
doc = Document.find(params[:id])
if doc.user_access?(current_user)
#document = doc
#this block will run fine and return #document to get method
else
flash[:alert] = msg
redirect_to root_url and return
#this block is giving you trouble because you are redirecting to root url and then control goes back to your get method where you are using redirect again and hence double render error
end
end
FIX:
If you are using it as a filter then to fix error you can do:
def get
#i think this is your main method so you should use redirect or render inside this method only
#instance variables set inside access_doc_or_redirect will automatically be available inside this method
if #document
redirect_to #document.file.url
else
flash[:alert] = "Sorry, no document view access."
redirect_to root_url
end
end
def access_doc_or_redirect
#doc = Document.find(params[:id])
if #doc.user_access?(current_user)
#document = doc
end
end

AbstractController::DoubleRenderError that shouldn't be

I've been getting the following error when I hit this destroy method in a my User controller.
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action.
Please note that you may only
call render OR redirect, and at most once per action. Also note that
neither redirect nor render terminate execution of the action, so if
you want to exit an action after redirecting, you need to do something
like "redirect_to(...) and return".):
It's a strange one, because I honestly am only responding once to the call.
Here's my action:
def destroy
user = User.find(params[:id])
if user.has_role_for? current_client
# then we remove the role
user.has_no_roles_for! current_client
# was that the users only role?
if user.roles.count == 0
user.destroy
end
respond_with head :ok
else
respond_with({:error=>'unauthorised'}, :status => :forbidden)
end
end
Any ideas?
Try adding " and return" after the respond_with lines:
respond_with head :ok and return
respond_with({:error=>'unauthorised'}, :status => :forbidden) and return
head(:ok) doesn't return something you can respond_with. head :ok renders a 200 with no body. respond_with renders via the responder some representation of the object you passed into it. head calls render, respond_with calls render, hence the double render error.
You should change that line to just head :ok.

Render different action for ajax vs html request in rails 3

In rails three I have the following code for my destroy action in a photos controller
def destroy
#photo = Photo.find(params[:id])
if #photo.destroy
flash[:notice] = t('photo.deleted')
respond_to do |format|
if request.xhr?
format.js
else
format.html {redirect_to photos_path}
end
end
else
flash[:alert] = t('.photo.error_deleting')
if request.xhr?
redirect_to(photos_url)
else
redirect_to(photo_path #photo)
end
end
end
The goal is essentially to redirect to the index page if this is called from a standard link and render destroy.js if called from a remote link.
This works but I was wondering if there is a cleaner way of doing this in rails 3. Possibly using the respond_with operator?
Thanks
This should work for you:
respond_to :html, :js
def destroy
#photo = Photo.find(params[:id])
if #photo.destroy
flash[:notice] = t('photo.deleted')
else
flash[:alert] = t('.photo.error_deleting')
end
respond_with(#photo)
end
There is a good blog post about it here:
http://ryandaigle.com/articles/2009/8/10/what-s-new-in-edge-rails-default-restful-rendering
Here's a quote from the post about the logic:
If the :html format was requested:
If it was a GET request, invoke render (which will display the view
template for the current action)
If it was a POST request and the resource has validation errors, render
:new (so the user can fix their
errors)
If it was a PUT request and the resource has validation errors, render
:edit (so the user can fix their
errors)
Else, redirect to the resource location (i.e. user_url)
If another format was requested, (i.e. :xml or :json)
If it was a GET request, invoke the :to_format method on the resource and
send that back
If the resource has validation errors, send back the errors in the
requested format with the
:unprocessable_entity status code
If it was a POST request, invoke the :to_format method on the resource and
send that back with the :created
status and the :location of the new
created resource
Else, send back the :ok response with no body
A little more on the to_format part from the documentation:
First we try to render a template, if
the template is not available, we
verify if the resource responds to
:to_format and display it.
There is also a Railscast about it:
http://railscasts.com/episodes/224-controllers-in-rails-3

Resources