Question

I am in the process of migrating some of my requests in my rails 4 app to ajax and am having a bit of trouble with a redirect.

On the home page I have a list of items that can be enabled/disabled, easy enough. This is all taken care with one of two links <%= link_to "disable", toggle_my_class_path(my_class), method: "PATCH", remote: true %>

In the ApplicationController I have a before_action that checks if the current user is logged and if not redirects them to the homepage where the log in form is displayed.

def require_login
  unless current_user
    redirect_to root_url, :notice => "Please log in"
  end
end

The issue is that (I think) because of the ajax call somehow the PATCH verb is being used instead of GET which is causing a route problem. Below is my log output from the call

Started PATCH "/my_class/2/toggle" for 127.0.0.1 at 2014-04-10 16:33:52 -0500
Processing by MyClassController#toggle as JS
  Parameters: {"id"=>"2"}
Can't verify CSRF token authenticity
   (0.1ms)  SELECT COUNT(*) FROM "users"
Redirected to http://localhost:3000/
Filter chain halted as :require_login rendered or redirected
Completed 302 Found in 9ms (ActiveRecord: 1.3ms)


Started PATCH "/" for 127.0.0.1 at 2014-04-10 16:33:56 -0500

ActionController::RoutingError (No route matches [PATCH] "/"):
  actionpack (4.0.0) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.0.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.0.0) lib/rails/rack/logger.rb:21:in `block in call'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `block in tagged'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:25:in `tagged'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `tagged'
  railties (4.0.0) lib/rails/rack/logger.rb:21:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
  rack (1.5.2) lib/rack/runtime.rb:17:in `call'
  activesupport (4.0.0) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
  rack (1.5.2) lib/rack/lock.rb:17:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/static.rb:64:in `call'
  railties (4.0.0) lib/rails/engine.rb:511:in `call'
  railties (4.0.0) lib/rails/application.rb:97:in `call'
  rack (1.5.2) lib/rack/lock.rb:17:in `call'
  rack (1.5.2) lib/rack/content_length.rb:14:in `call'
  rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service'
  /home/***/.rvm/rubies/ruby-head/lib/ruby/2.1.0/webrick/httpserver.rb:138:in `service'
  /home/***/.rvm/rubies/ruby-head/lib/ruby/2.1.0/webrick/httpserver.rb:94:in `run'
  /home/***/.rvm/rubies/ruby-head/lib/ruby/2.1.0/webrick/server.rb:295:in `block in start_thread'

You can see that ActionController::RoutingError (No route matches [PATCH] "/"): is the issue

I'm not sure of a way around this. I don't want the PATCH verb to be used however I can't seem to find a way to specify the verb in redirect_to

Any thoughts?

Was it helpful?

Solution

You can't redirect from server side (controller) within an ajax call. Everything retrieved via javascript returns to javacript; the web browser is expecting some javascript to be evaluated.

So you need to perform that redirect using javascript.

For example, you can change the before_action (code not tested):

def require_login
  unless current_user
    if request.xhr?
      flash[:notice] = "Please log in"
      flash.keep(:notice) # Keep flash notice for the redirect
      render js: "window.location = #{root_url.to_json}" # js to be evaluated
    else
      redirect_to root_url, :notice => "Please log in"
    end
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top