views:

708

answers:

4

OK, as is often the case, I have a controller action in my app that is protected from unauthorized access by a before_filter. The only thing is that I need to redirect this action if another condition is true:

class Payment < ApplicationController
  before_filter login_required

  def new
    redirect_to some_other_path if @order.is_free?
    @payment = Payment.new
  end
end

In my testing, I check to make sure that the action is correctly protected, however, it is also the case that the @order.is_free statement is true. When this is the case, I get the following error:

`render_with_no_layout': Can only render or redirect once per action

Is there any way of checking to make sure I'm not already redirecting or to override an existing redirect?

A: 

I don't think your before filter is what causes the double render error. Take a look at this example:

class PostsController < ApplicationController
  before_filter :perform_a_redirect, :except => [:wtf]

  def index
    redirect_to 'http://google.com'
  end

  def wtf
    render :text => 'wtf'
  end

  private

  def perform_a_redirect
    redirect_to :action => 'wtf'
  end
end

When visiting /posts, I get redirected to /posts/wtf. No double render error. Assuming your 'login_required' method only redirects/renders once, I suspect that the code you are posting here is not the problem, but that something else is causing this.

August Lilleaas
+2  A: 

I am assuming that the login_required method performs a redirect if the user is not logged in. In which case:

Your before filter should return false after calling redirect. This will prevent the new action from ever being called. Later versions of rails automatically do this if you call render or redirect in a before_filter, so maybe you are using an older version.

Also you should return after the call to redirect in the new handler, unless you want to always create a new Payment object.

Noel Walters
A: 

The before filter is a red herring. When @order_is_free? the code is both setting up a redirect and falling through to a rendering of new. The redirect statement doesn't control the flow of the method. Add a return statement after the redirect, or you can even return the redirect, as in return(redirect_to :action => :show, :id => @order, :controller => :free_orders)

+1  A: 

Your class should be PaymentController, not Payment. The reason for this is so the controller class and model class do not clash.

Ryan Bigg