Michal
Michal

Reputation: 677

redirect_to from "destroy" to "index"

Problem appears when I want to remove element from paginated table in "ajaxized" way. My tasks controller calls its destroy method in response to [DELETE] /tasks/1234, but at the end I want to redirect to index to get the list automatically refreshed.

Unfortunately, what redirect_to tasks_url at this point does is [DELETE] /tasks request.

Is there any way to force GET request instead of DELETE while redirecting from inside of destroy ?

Upvotes: 14

Views: 5530

Answers (6)

vitor.caetano
vitor.caetano

Reputation: 239

Use redirect_to with status 303

def destroy
  @task = Task.find(params[:id])
  @task.destroy
  redirect_to :action => :index, status: 303     
end

redirect_to documentation says:

http://api.rubyonrails.org/classes/ActionController/Redirecting.html

If you are using XHR requests other than GET or POST and redirecting after the request then some browsers will follow the redirect using the original request method. This may lead to undesirable behavior such as a double DELETE. To work around this you can return a 303 See Other status code which will be followed using a GET request.

Upvotes: 23

Michal
Michal

Reputation: 677

Ok, so to sum up this question. The easiest way I found to fix the issue, is to mess a bit in routes.rb by adding: "tasks" => "tasks#index", :via => :get and to use redirect_to tasks_url (in my case) directly in destroy action in controller.

This will solve the problem with kaminari pager as well (which renders strange links in some cases).

Upvotes: 1

Mark Swardstrom
Mark Swardstrom

Reputation: 18080

You probably don't want to do a standard rails redirect when using ajax. This blog post has some good insight on the issue and solutions. Note this is from a similar question in January, answered by DGM

Upvotes: 0

melekes
melekes

Reputation: 1888

Why not to use :action param ?

def destroy
  @task = Task.find(params[:id])
  @task.destroy
  redirect_to :action => :index    
end

Upvotes: 0

flooooo
flooooo

Reputation: 709

I think you should rearrange your code on the client side:

  1. Memorize current page
  2. fire destroy action, await true or false
  3. request index at memorized page using ajax call.

Upvotes: 0

Reuben
Reuben

Reputation: 53

Don't use redirect. Use render. Abstract the functionality to get the table data into a library module and then call that from both index as well as the delete methods, and then add then add the render call to the delete method so that the index view is what is sent back in response.

require 'myLibrary'
include myModule

def index
    getTableData
end

def destroy
    flash.now[:notice] = "Delete operation failed" unless Task.destroy(params[:id])
    getTableData
    render 'myController/index'
end

in lib/myLibrary

module myModule
    def getTableData
        # Table Foo here
    end
end

Upvotes: 3

Related Questions