Topic: link_to_remote and before_filter issue

I'm using acts_as_authenticated and acts_as_rateable.

When I use the link_to the acts_as_rateable plugin would confirm that a user is logged in. If not it would redirect the user to the login page.

I have converted the link_to to link_to_remote and it no longer checks to see if the user is logged in. I have added a before_filter :login_required; however, nothing happens. I look through the log file and it says that it is redirecting the users to the login page; however, the page is not redirected to the login page.

Anyone have any idea why the login page isn't showing up with the link_to_remote?

Processing RatingController#rate (for 127.0.0.1 at 2007-04-30 15:38:22) [POST]
  Session ID: 76289b0dcc495eaecccf668430233e8f
  Parameters: {"rating"=>"1", "rateable_type"=>"MyObject", "action"=>"rate", "id"=>"4", "controller"=>"rating"}
DEPRECATION WARNING: The :dependent => true option is deprecated and will be removed from Rails 2.0.  Please use :dependent => :destroy instead.  See http://www.rubyonrails.org/deprecation for details.  See http://www.rubyonrails.org/deprecation for details. (called from has_many at ./script/../config/../vendor/rails/activerecord/lib/active_record/associations.rb:558)
Redirected to http://localhost:3000/account/login
Filter chain halted as [#<ActionController::Filters::ClassMethods::SymbolFilter:0x46e3b70 @filter=:login_required>] returned false.
Completed in 0.13100 (7 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/rating/rate/4?rateable_type=Campaign&rating=1]


Processing AccountController#login (for 127.0.0.1 at 2007-04-30 15:38:23) [GET]
  Session ID: 76289b0dcc495eaecccf668430233e8f
  Parameters: {"action"=>"login", "controller"=>"account"}
Rendering  within layouts/account
Rendering account/login
  User Columns (0.020000)   SHOW FIELDS FROM users
  User Load (0.020000)   SELECT * FROM users WHERE (users.`id` IS NULL) LIMIT 1
Rendered account/_login (0.78100)
Rendered layouts/_header (0.01000)
Rendered layouts/_footer (0.01000)
Completed in 0.82100 (1 reqs/sec) | Rendering: 0.77100 (93%) | DB: 0.04000 (4%) | 200 OK [http://localhost/account/login]


Ryan
http://blog.aisleten.com/
http://www.obsidianportal.com

Last edited by felttippin (2007-04-30 19:04:32)

Re: link_to_remote and before_filter issue

AJAX isn't designed to handle 302 redirects, you'll have to handle this differently.

If you're using RJS, check out the redirect_to method for that.

If you aren't using RJS, this will be quite a bit trickier, and I recommend you just start using RJS. smile

Railscasts - Free Ruby on Rails Screencasts

Re: link_to_remote and before_filter issue

So AJAX doesn't work with the before_filter :login_required?

I'm not using RJS, but I am doing some AJAX update stuff in the rating_controller.rb (render :update do |page| section). The reason I'm not using RJS in this instance is because I have to pass an object as a local to the partial. Any thoughts on how to do this?

class RatingController < ApplicationController
    before_filter :get_class_by_name
    before_filter :login_required # Doesn't work with AJAX

  def rate
    return unless logged_in? # Need to handle this better with an error message
   
    rateable = @rateable_class.find(params[:id])
   
    # Delete the old ratings
    Rating.delete_all(["rateable_type = ? AND rateable_id = ? AND user_id = ?", @rateable_class.base_class.to_s, params[:id], @current_user.id])
    @r = Rating.new
    @r.rateable = rateable
    @r.rating = params[:rating]
    @r.user_id = current_user.id
    @r.save
   
    render :update do |page|
        page.replace_html "ratings-block-#{rateable.id}", :partial => "rate", :locals => { :asset => rateable }
        page.visual_effect :highlight, "ratings-block-#{rateable.id}"
    end

    ...
   
  end
end

Re: link_to_remote and before_filter issue

felttippin wrote:

So AJAX doesn't work with the before_filter :login_required?

Well it doesn't handle redirects properly, so correct, it doesn't work with the before_filter.

felttippin wrote:

I'm not using RJS, but I am doing some AJAX update stuff in the rating_controller.rb (render :update do |page| section). The reason I'm not using RJS in this instance is because I have to pass an object as a local to the partial. Any thoughts on how to do this?

Looks like you're using RJS here, it's just inline so it's not in a separate file - still RJS. In the before filter you can do this (I think, haven't tested it).

def login_required
  unless logged_in?
    if request.xhr? # an AJAX request
      render :update { |page| page.redirect_to .... }
    else
      redirect_to ...
    end
    false # return false so action isn't called
  end
end

See if that works for you. You might be able to use respond_to as well instead of the xhr? check, but I'm not sure.

Railscasts - Free Ruby on Rails Screencasts

Re: link_to_remote and before_filter issue

Ryanb,

Thanks for your help. It definitely put me on the right track.

The issue was exactly what you had written. The acts_as_authenticated plugin has a method called access_denied where it looks at the format of the request.

I added the following lines to that function and now the before_filter :login_required works!

accepts.js do  
  render(:update) { |page| page.redirect_to(:controller => '/account', :action => 'login') } 
end

So the full function looks like this:

def access_denied
  respond_to do |accepts|
    accepts.html do
      store_location
      redirect_to :controller => '/account', :action => 'login'
    end
    accepts.js do
      render(:update) { |page| page.redirect_to(:controller => '/account', :action => 'login') }
    end
    accepts.xml do
      headers["Status"]           = "Unauthorized"
      headers["WWW-Authenticate"] = %(Basic realm="Web Password")
      render :text => "Could't authenticate you", :status => '401 Unauthorized'
    end
  end
  false
end

Thanks again for the help!

Re: link_to_remote and before_filter issue

I added store_location to you solution with accepts.js like this:

accepts.js do
   store_location
   render(:update) { |page| page.redirect_to(:controller => '/account', :action => 'login') }
end

But once I login the app doesn't get me back to where I was. It just sends me to default. Any ideas?

Last edited by cyberf (2007-05-19 07:36:32)

Re: link_to_remote and before_filter issue

I had attempted to do the same; however, it stores the location of the partial that's being called an not the original page + action.

For now I've just left out the store_location and the user has to redo their action. I've been trying to figure out a way to store the original location + action being called so that when I redirect back to the originating page I can call the rate function.

If anyone else has any ideas, please chime in.

In the mean time I've put up an extensive blog post on getting it the rest of it up an working:

http://blog.aisleten.com/2007/05/03/aja … _rateable/

Ryan
http://blog.aisleten.com/

Re: link_to_remote and before_filter issue

Good to know I'm not alone smile

Re: link_to_remote and before_filter issue

I know this is an old post, but I ran into the same problem myself. I got around the problem by creating a separate function "return_to_location" which uses HTTP_REFERER (that misspelling will always bother me) instead of REQUEST_URI.

       
accepts.js do 
   return_to_location
   render(:update) { |page| page.redirect_to(:controller => '/account', :action => 'login') } 
end

def return_to_location
   session[:return_to] = request.env["HTTP_REFERER"]
end