Rails Devise Authentication Token with AJAX - ajax

I'm making AJAX based application with Devise as authentication system. The problem I encountered is that when I sign in with Devise with AJAX, then when view changes and log out button appears it's showing this error when clicked:
ActionController::InvalidAuthenticityToken in Customization::SessionsController#destroy
ActionController::InvalidAuthenticityToken
Parameters:
{"_method"=>"delete",
"authenticity_token"=>"hitX5aEjoTzi3tKP3y76+c60MuJumv5mwNEjyGUOQiY="}
Here you have my devise session controller's create method for signing in (I had to change few things to make AJAX happen):
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
yield resource if block_given?
if user_signed_in?
flash[:logged] = "Zalogowany"
respond_to do |format|
format.html { redirect_to root_path }
format.js { render "sign_in_success.js.erb" }
end
end
end
sign_in_success.js.erb file:
$("body").empty();
$("body").append("<%= j(render template: 'layouts/user') %>");
button inside "layouts/user":
a href="#{destroy_user_session_path}" data-method="delete" rel="nofollow"
button.btn.btn-primary.m-r-20 type="button"
b Log Out
How do I send Authenticity Token with AJAX? Can I send it to "layouts/user" via locals option in render and use it this way?

I have solution. The problem was that csrf_meta_tags, was not updated when new session was created. The solution to that problem was to include additional code inside sign_in_success.js.erb file:
$("body").empty();
$("meta[name='csrf-token']").remove()
$("meta[name='csrf-param']").remove()
$("head").append("<meta name='csrf-token' content='<%= form_authenticity_token %>'>");
$("head").append("<meta name='csrf-param' content='<%= request_forgery_protection_token %>'>");
$("body").append("<%= j(render template: 'user/logged_signed') %>");
With code seen above firstly we are empting body element , then we are removing from DOM meta tags created by csrf_meta_tags helper. After that we are manually adding new csrf-token and csrf-param, this time our new authenticity token is assigned to meta name="csrf-token".
After that when we click on our log_out button rendered by "user/logged_signed" template we are logged out successfully and back at our root_path.

Related

Render PDF on custom controller action using wicked_pdf

This may end up being very simple but I have been trying to figure this out to no avail. I am using wicked_pdf to render pdfs on html pages. When I do this the restful way by adding the respond_to block to a controllers show action everything works fine when going to controller/id.pdf.
What I am trying to do however, is use the respond_to block on a custom controller action. I have a reports controller which has many reports and custom actions. One of these reports has a form which is submitted to another custom controller action to render the report. This all works fine with the html render however, when I added the respond_to block to this custom action it simply tells me it cannot find the show action for that controller. Below is the related code:
routes.rb
resources :reports do
collection do
get 'customer_summary'
post 'summary_report'
end
end
reports_controller.rb
def summary_report
#tickets = tickets
respond_to do |format|
format.html
format.pdf do
render pdf: "summary_report", header: {spacing: 10, html: {template: 'shared/header'}}, footer: {html: {template: 'shared/footer'}}, margin: { top: 20, bottom: 20 }
end
end
The templates exsist as well as the summary_report.pdf.haml file. What am I doing wrong? Thank you in advance for your help!

Rails 4 form remote update div issue

I'm having some problems to update my div after submitting a form with Rails 4. Here is the relevant part of my code:
View:
_details.html.haml
= form_tag(url_for(save_answer_path(format: :js)), remote: true) do
(some html code ....)
= submit_tag t('app.bouton.send'), id: 'sendButton'
%div#divlogs
= render partial: 'logs'
Controller:
def save_answer
some code ...
respond_to do |format|
format.js
end
end
JS:
save_answer.js.erb
$('#divlogs').html("<%= escape_javascript(render partial: 'logs') %>");
When I submit, everything is called correctly but I'am getting an incorrect output. What I want is to update my div, but instead I get a page with what I have on my JS file, but with the content of my partial.
Example:
My URL after submitting:
http://domaine/controller/save_answer.js
What I get on the screen:
$('#divlogs').html("<p>This should appear on the div </p>");
Does anyone know what is going on?
Solution:
As #VladKhomich said in the comments above, I was missing the JS file rails.js.
You can download it from here: https://github.com/rails/jquery-ujs/blob/master/src/rails.js

how to prevent redirect to index.html after log in or sign up?

I recently implemented a new homepage (index.html) on my rails app (into folder public/index.html) with /signin and /signup paths. Before I implemented index.html on my website, I have been redirecting users to root_url (which is home.html.erb) after sign in or sign up.
When they sign out, I've been redirecting them to root_path.
The problem is that after this new index.html, when users try to log in or sign up, they get redirected back to index.html. Is there a place to have them log in successfully to the original root_url without requiring many code edits?
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to root_path
else
flash.now[:error] = "Invalid email/password combination"
render 'new'
end
end
def destroy
sign_out
redirect_to root_path
end
end
UsersController
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
flash[:success] = "Welcome!"
redirect_to root_path
else
render 'new'
end
end
This is what I have in my routes.rb
root to: 'static_pages#home'
First off the only difference between root_url and root_path (and in general between foo_url and foo_path) is that the former is a full url (i.e. http://example.com/...) whereas the latter is just the path (the bit after the hostname). For a simple redirect they'll have the same result.
If public/index.html exists then that is where visits to '/', (i.e. root_path) will go.
If you want users to be sent to a different page after signup then change your redirect. For example if your routes file had
get '/home' => 'home#index', :as => :home
then redirecting to home_path would send people to the index action of the home controller.
The problem seems to be that your public/index.html overrides your root_path Rails route.
You cannot access the root_path if there is a file called index.html in your public directory.
You need to rename index.html to something else or use another path other than your root_path
EDIT:
Another option is to have two different erb templates for the root_path. Then in the controller action for the root_path, you could do this:
class StaticPages < ApplicationController
def home
if user_signed_in?
render 'home_signed_in'
else
render 'home_signed_out'
end
end
end
You would then need to create two erb templates at,
/app/views/static_pages/home_signed_in.html.erb
and
/app/views/static_pages/home_signed_out.html.erb
You would also need to define or replace the user_signed_in? method in my example code with your own method to detect if the user is signed in. And don't forget to remove /public/index.html
Try to change root_path with home_ControllerName_path, where ControllerName must be the name of the controller handling the home action.
go to your routes.rb file and make following change
root :to => 'main#home_page'
you can redirect to any route by modifying root: in config/routes.rb file

Simple example of Rails 3 + UJS using Ajax to make a remote call, and rendering the resulting JSON object

I'm trying to add some Ajax functionality in my Rails 3 app.
Specifically, I want a button that will submit an Ajax request to call a remote function in my controller, which subsequently queries an API and returns a JSON object to the page.
Once I receive the JSON object I want to display the contents.
All of this with the new Rails 3 UJS approach, too. Is there a good example/tutorial for this online somewhere? I haven't been able to find one on google. A simple example using a button as the entry point (ie, the user clicks the button to start this process) would work, too.
Edit
Let me try this with a different approach. I want to have this button query an external API, which returns JSON, and display that JSON on the page. I have no idea where to even begin. Does the button itself query the external API? Do I need to go through the controller, and have the controller query the external API, get the JSON, and give the JSON back to this page? How do I display/access the contents of this JSON? I honestly can't find a good Rails 3.x example of how to handle JSON...
Here is a start:
First create your button with a link_to method in your view, for example:
=link_to "delete", "#{invitation_path(invitation)}.json", :method=>:delete, :remote=>true, :class=>"remove", :confirm=>'Are you sure you?'
Note that I am appending ".json" to the url of my resource. This is just an example of a an AJAX delete, google link_to to see the meaning of the parameters. The concept if that you make your HTTP request with the parameter :remote set to true, in other words this is translated to an AJAX call from your browser.
Second, write some javascript so that you can process what ever is the result of the AJAX call your browser will make when the user click on the link_to of step 1. For details you can see this blog post: http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
An example from my site:
jQuery(function($) {
// create a convenient toggleLoading function
var toggleLoading = function() { $("#loading").toggle() };
$("#pending_invitation")
.live("ajax:loading", toggleLoading)
.live("ajax:complete", toggleLoading)
.live("ajax:success", function(event, data, status, xhr) {
var response = JSON.parse(xhr.responseText)
if (response.result == "ok") {
$(this).fadeOut('fast');
}
else {
var errors = $('<div id="error_explanation"/>');
errors.append('<h2>Pending invitation action error</h2><ul><li>' + response.error + '</li></ul>');
$('#new_invitation_error').append(errors)
}
});
});
where you can see that I parse the returned json and and change the html on the page based on that. Note that this js uses the CCS ids and classes defined in the top view that is not included here.
If you now want to write you own controller to spit out the json here is an example:
class InvitationsController < ApplicationController
respond_to :html, :json
# other methods here
# ...
def destroy
#invitation = Invitation.find(params[:id])
respond_to do |format|
if #invitation
#invitation.destroy
flash[:success] = I18n.t 'invitations.destroy.success'
format.json { render :json =>{:result => "ok", :message=>"Invitation #{params[:id]} was destroyed", :resource_id=>params[:id] } }
else
format.json { render :json => { :result=>"failed", :error=>"Cannot find Invitation #{params[:id]}", :resource_id=>params[:id] } }
end
end
end
end
Hope this help.
Old question, but a really good overview of Ajaxifying Rails applications is:
Ajax in Rails 3.1 - A Roadmap
Also consider returning errors in the following format:
render :json => #myobject.to_json, :status => :unprocessable_entity
This will ensure that your client can process the response as an error.

Form validation errors in Rails 3

I have a form I built using Formtastic in Rails 3. The form submits to the #create action of ClientsController, and if the save is successful the controller redirects to a "thank you" page. If the save is not successful, it redirects to the page where the form is embedded. I'd like to be able to show the validation errors inline on the form page, but after the redirect back to that page, the errors object comes back empty.
What can I do so I can display the validation errors on the form?
Here is the code from the controller.
if client.save && event.save
redirect_to "/thank-you"
else
redirect_to :back
end
Some additional details: I am using RefineryCMS so there is no view for the page where the form is, and therefore I can't render the view.
You need to save your errors into session.
if client.save && event.save
session[:client_create_errors] = nil
redirect_to "/thank-you"
else
session[:client_create_errors] = client.errors
redirect_to :back
end
now you can access errors object from anywere using session[:client_create_errors]
Why not:
render :action => 'name-of-the-view-the-form-is-in'
instead of the redirect_to :back ?

Resources