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 ?
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.
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
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).
I think you should rearrange your code on the client side:
Memorize current page
fire destroy action, await true or false
request index at memorized page using ajax call.
Why not to use :action param ?
def destroy
#task = Task.find(params[:id])
#task.destroy
redirect_to :action => :index
end
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
Related
Route defined as follows
resources :purchases do
collection do
put :wirecardtest
end
end
Controller actions redirect in one of the following manners with associated error generated
format.html { redirect_to wirecardtest_purchase_path(#purchase)
undefined method `wirecardtest_purchase_path'
format.html { redirect_to wirecardtest_purchases_path(#purchase)
/purchases/wirecardtest.44
Behaviour is identical when putting code in view.
The ressource is defined in plural mode, as it ought to be. The redirect, as it is supposed to call a specific ressource should call the singular model-action mode (in plural it would generate the period).
I don't understand how I got into this damned-if-you-do, damned-if-you-don't position.
wirecardtest_purchases PUT /purchases/wirecardtest(.:format) purchases#wirecardtest
That's your mistake right there.. the path is generated as 'wirecardtest_purchases' but you are using 'wirecardtest_purchase' note the missing 's' to pluralize the 'purchase'.
Remember its a collection. So the path method is pluralized by rails.
When in doubt rake routes :)
---Update---
Improving the answer (check comments). Need here is to actually define a route as :member and not a :collection if you want to act upon a single object. Referring to Rails Docs,
resources ::purchases do
member do
get 'wirecardtest'
end
end
I am setting session[:return_to] for a lot of my routes to take users back to where they were before. I'm trying to create a generic checker to make sure that the link is valid, not the format, (http://somevalidurl) I don't care about that but that the actual link exists.
The main problem is when they are on a show page and then go to the edit page and delete an entry, the return_to takes them back to show page and we get a routing error because the entry no longer exists.
I would think that Rails had some sort of system for this in place.
I have something like this:
Net::HTTP.get_response(URI.parse(session[:return_to])) rescue false
But that takes forever to check and the page ends up taking a long time to refresh.
Ideas are welcome.
Checking if a previous url is valid is unnecessary, because such cases are not common routes to use your app. They are just exceptions. You only need a plan when exceptions happens, instead of dealing with it in every common route.
Simple solution: redirect to root
class ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found
redirect_to root_path, alert: "The record does not exist"
end
end
Advanced solution: redirect to controller's index page
class ApplicationController
rescue_from ActiveRecord::RecordNotFound do |exception|
# The message like: "Couldn't find foo with id=123"
klass = exception.message.split(' ')[2]
if klass
# suppose your index path is conventional foos_path
path = send "#{klass.pluralize.underscore}_path"
else
path = root_path
end
redirect_to path
end
end
I've been pulling my hair out trying to get anything working with "def create" and "def update" in the users_controller.rb for Devise.
For instance, I've tried this:
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = "Test Save"
else
flash[:notice] = "Test Error"
end
end
end
I've used this code along with the appropriate code to show flash notices in the views section. However nothing is shown when I either submit a blank form, an incomplete form, or a complete form. The user registration will still go through on a complete form, but it does not follow anything I put in "def create". I've tried other ways of testing this aside from flash notices, such as sending to a different page, etc. I get no response. The same thing for "def update", it doesn't seem to even use that code.
I'm completely dumbfounded on this one, any ideas?
If i understand your question correctly, you should be overwriting the devise controller.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
# add custom create logic here
end
def update
super
end
end
You can see what the default devise controllers are doing here:
https://github.com/plataformatec/devise/tree/master/app/controllers/devise
If you just want to edit the flash message, looking at the link above shows that devise uses a method called set_flash_message
# Sets the flash message with :key, using I18n. By default you are able
# to setup your messages using specific resource scope, and if no one is
# found we look to default scope.
# Example (i18n locale file):
#
# en:
# devise:
# registrations:
# signed_up: 'Welcome! You have signed up successfully.'
So you can just edit your devise.en.yml file with the correct text and voila!
Note: If you do overwrite the controller don't forget to also add
# app/config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
How about this instead?
if #user.save
redirect_to #user, notice: 'User was successfully created.'
else
render action: 'new'
end
You are setting the flash, but no redirection and no rendering. I'm wondering if you are getting a blank page, or a 200 with no body.
This will redirect to the show action, setting a flash notice if successful and render the new form with the #user.errors showing why it failed.
If you are using devise, you could use the Registrations Controller to create a new account, you shouldn't need to create a new one. If you create a new one, there might be a conflict in the routes with registrations#create and users#create both pointing to POST /users
I have a double namespace situation, where my controllers look like this:
CandidateController
Candidate::PerformanceController
Candidate::Performance::ReviewController
In Rails 2, I was able to use redirect_to from the Candidate::Performance::ReviewController controller in order to redirect to an action in the CandidateController, like so:
class Candidate::Performance::ReviewController < ApplicationController
before_filter :ensure_manager
# ...
def ensure_manager
if !current_user.manager?
flash[:warning] = t(:must_be_manager)
redirect_to :controller => '/candidate', :action => :index
end
end
end
The / in controller => '/candidate' would allow Rails to redirect from app.com/performance/reviews to app.com/candidate.
However, this seems to not work the same in Rails 3.1. Instead, my redirect_to goes to app.com/candidate//candidate. What is the correct way to specify a "absolute" controller within a redirect_to hash (ie. without using a path helper)?
Update: I know this would be infinitely easier if I just use named route helpers (ie. candidate_path). Unfortunately, there is a lot of legacy code in our codebase which doesn't use RESTful routing and instead uses the default "catch-all" route; ie. we have a lot of actions with no named route to fallback on.
I wonder if something else is wrong. In the doc:
In particular, a leading slash ensures no namespace is assumed. Thus,
while url_for :controller => ‘users‘ may resolve to
Admin::UsersController if the current controller lives under that
module, url_for :controller => ’/users‘ ensures you link to
::UsersController no matter what.
And I don't think it changed...
Also, shouldn't the catch-all routes be after the default routes in your config?
I think that redirect_to :controller => ... uses url_for to build the url, so in the end, if your custom routes catches /candidates, I don't really see the difference.
Some people have the same problem: https://github.com/rails/rails/issues/2575
Patching actionpack/lib/action_dispatch/routing/route_set.rb line 434
as follows fixes this: if !named_route && different_controller? &&
!controller.starts_with?('/')
If anyone else runs into this problem, it seems to be a known issue (unsure whether they consider it a bug or not, given the lack of response on the issue page from anyone working on Rails).
Until they patch it (assuming they do), I've added the following little monkey patch into an initializer, based on the code given in the original post of that issue:
module ActionDispatch
module Routing
class RouteSet
class Generator
def use_relative_controller_with_absolute_paths!
return if controller.starts_with?('/')
use_relative_controller_without_absolute_paths!
end
alias_method_chain :use_relative_controller!, :absolute_paths
end
end
end
end
Hope this can help someone else!
Update: It seems that this was fixed in Rails here.
I have a before_filter that checks the validity of an API key. If the key is invalid, I'd like to render a header-only 403 response.
In my controller:
before_filter :validate_api
...
def validate_api
if params[:api_key].present? and ApiKey.find(params[:api_key])
return true
else
render head :forbidden
end
end
The problem is that I get a DoubleRender error, presumably when Rails goes into the action and attempts to render the response anyways. It was my understanding that Rails prevents execution of the action if a before_filter renders or redirects. Is that not the case?
How do I render a header-only response in a before_filter and prevent actions from being executed?
Have you tried returning false in the else part?