Rails 5 - how to implement ajax flash message for devise - ruby-on-rails

I am making a rails5 blog app with devise. In the comments controller, I check if the user exists using "before_action :authenticate_user!".
So, if the user is logged in then create comment method gets executed and the server response gets send back to the client via AJAX. However, if the user is not logged in then "before_action :authenticate_user!" check creates a 401 authentication error in the response ( can be seen in the browser log).
I want to just display the flash message just above the comment box or somewhere on the page so that user knows that he/she can not enter a comment without logged in.
There are many similar questions I have found but they seem very confusing and none of the solutions worked for me. Most of them talk about the changing the devise confg (e.g. config.http_authenticatable_on_xhr = false) or override the authenticate_user method etc.
Can someone just explain is it possible to show a flash message warning to the user to login to add comment (ajax call). I don't want automatic redirect for AJAX calls.

Create a flash method then catch the unauthorized error in jQuery and show your flash message :
#flash = (content, type) ->
content = "<div class='container'><div class=\"alert alert-#{type}\">#{content}</div></div>" if type?
$('#flash').clearQueue().hide().html(content).fadeIn('slow').delay(3000).fadeOut('slow')
$(document).ajaxError (e, xhr, settings) ->
flash("Unauthorized", "danger") if xhr.status == 401

Related

Remove specific error message from Rails Devise

In Devise, when confirmation instructions are resent and the email doesn't exist in the database, we get the error
Email not found
However, due to security, I want to remove this specific error.
I'm using custom controllers but the confirmation#create method is just invoking super.
Under that, I've removed the email field from the errors using
resource.errors.delete('email')
Printing out the errors (in the controller) after the fact shows nothing for email. However, when the request goes through and I print the resource.errors object in the shared errors partial, the error is still there.
Is there any way to remove this error completely? I'm assuming some other action is happening after the #create method that's injecting the error again.
Full method
def create
super
resource.errors.delete('email')
end
Confirmation of deletion:
Confirmation that error persists after redirect:

Ruby on Rails view Facebook Event without user login

I'm putting together a website which displays Facebook events using Ruby on Rails and Koala.
I can display an event just fine if I do the following:
graph = Koala::Facebook::API.new(auth_token)
fb_event = graph.get_object(some_event_id)
But as soon as I change the first line to:
graph = Koala::Facebook::API.new(auth_token)
Ie, without the auth_token, I get an error--> type: OAuthException, code: 104, message: An access token is required to request this resource. [HTTP 400]
I don't want the user to have to be logged in in order to view the event. I know that I don't have to be logged into Facebook to view the event, so I'm sure there must be way to get the event without having to have the user be logged in. Any ideas?
Using WizKid's comment to get me there:
I went to https://developers.facebook.com/tools/access_token/
I then used my app's "User Token"

How can I test Stripe.js using poltergeist and Capybara?

I've been going nuts trying to write an automated test for my user sign up page. Users will be charged a recurring subscription via Stripe. They input their basic details (email, password, etc) and their credit card details on the same form, then the following flow happens:
(On the client-side) stripe.js makes an AJAX request to Stripe's servers, which (assuming everything is valid) returns a credit card token.
My javascript fills in a hidden input in the HTML form with the credit card token, and submits the form to my Rails server.
(Now on the server-side): I validate the user's basic details. If they're invalid, return (because there's no point charging them via Stripe if e.g. their email address is invalid so they can't create an account anyway.)
If they're valid, attempt to create a Stripe::Customer object, add the right subscription and charge them using Stripe's ruby gem etc.
All of this works perfectly fine... except I can't figure out how to test it. Testing step #4 is easy enough as it takes place on the server-side so I can mock out the Stripe calls with a gem like VCR.
Step #1 is what's giving me trouble. I've tried to test this using both puffing-billy and the stripe-ruby-mock gem, but nothing works. Here's my own javascript (simplified):
var stripeResponseHandler = function (status, response) {
console.log("response handler called");
if (response.error) {
// show the errors on the form
} else {
// insert the token into the form so it gets submitted to the server
$("#credit_card_token").val(response.id);
// Now submit the form.
$form.get(0).submit();
}
}
$form.submit(function (event) {
// Disable the submit button to prevent repeated clicks
$submitBtn.prop("disabled", true);
event.preventDefault();
console.log("creating token...");
Stripe.createToken(
// Get the credit card details from the form
// and input them here.
}, stripeResponseHandler);
// Prevent the form from submitting the normal way.
return false;
});
Just to reiterate, this all works fine when I test it manually. But my automated tests fail:
Failure/Error: expect{submit_form}.to change{User.count}.by(1)
expected result to have changed by 1, but was changed by 0
When I try to use the gem puffing-billy, it seems to be caching stripe.js itself (which is loaded from Stripe's own servers at js.stripe.com, not served from my own app, as Stripe don't support this.), but the call initiated by Stripe.createToken isn't being cached. In fact, when I log into my Stripe server logs, it doesn't seem that the call is even been made (or at least Stripe isn't receiving it.)
Note those console.log statements in my JS above. When I run my test suite, the line "creating token..." gets printed, but "response handler called." doesn't. Looks like the response handler is never being called.
I've left out some details because this question is already very long, but can add more on request. What am I doing wrong here? How can I test my sign up page?
UPDATE See [my comment on this Github issue] on stripe-ruby-mock for more info on what I've tried and failed.
If I understand correctly...
Capybara won't know about your ajax requests. You should be able to stub out AJAX requests with Sinatra. Have it return a fixtures much the same as VCR.
Here's an article on it.
https://robots.thoughtbot.com/using-capybara-to-test-javascript-that-makes-http
You need to boot the Sinatra app in Capybara and then match the URLs in your ajax calls.
Something like:
class FakeContinousIntegration < Sinatra::Base
def self.boot
instance = new
Capybara::Server.new(instance).tap { |server| server.boot }
end
get '/some/ajax'
# send ajax back to capybara
end
end
When you boot the server, it will return the address and port which you can write to a config that your js can use.
#server = App.boot
Then I use the address and port to config the JS app
def write_js_config
config['api'] = "http://#{#server.host}:#{#server.port}"
config.to_json
end
In spec_helper.rb send in the config to the js so your script points to your sinatra app. Mine compiles with gulp. So I just build the config into to is before the tests run:
system('gulp build --env capybara')
I've had tests which worked on manual fail in Capybara/poltergeist due to timeout. In my case, the solution was to wait for all AJAX requests to finish. Reference
Not sure whether Stripe.js uses JQuery internally, try checking for a condition set by stripeResponseHandler.
In addition to the wait_for_ajax trick mentioned, it looks like you are calling expect before your database was updated. One way to check that would be to add a breakpoint in your code(binding.pry), and check if it is a race condition issue or not.
Also, as per Capybara's documentation, introducing an expectation of a UI change makes it 'smartly' wait for ajax calls to finish:
expect(page).not_to have_content('Enter credit card details')

How do I perform validation on an api call while submitting form and produce necessary error message?

My web app is an add-on service to another existing web-app.
Users may sign up to my web-app but first I must check if they are registered on the dependent web app.
I can do so by getting their username/password key and send it as parameters in an API CALL. If the call succeeds it returns their API TOKEN(to be used for further requests) else it returns a 404 error. If I receive the 404 error I'll just handle the exception by putting the error in a flash message.
How do I do this after the form is submitted?
I should generate an error which shows that the user is not registered on the web-app which my web-app depends on.
Instead of relying to ActiveModel's validations you do it yourself.
In your controller action:
def sign_in
# Assuming you issuing an HTTP request (HTTParty or Net::HTTP or your custom API handler)
#errors = []
response = MyAPI.sign_in(params[:username], params[:password])
if response.code == 200
# all good.. store response's API token for future requests
# and redirect to success path or render a view...
else
#errors << 'Sign in failed, please register on the other app first'
end
end
In your views you can easily then check whether #errors is empty. If not, display the error messages. You might of course want more fine-grained checks, e.g. responding differently for different failures (40x, 50x).

Send an asynchronous email

How can I send an asynchronous email with rails 4? By that I mean, when I click the 'send' button of a contact form, the page doesn't refresh, but the email is validated and sent, and a message is flashed to the user.
I've configured action_mailer correctly, and have a ContactForm mailer with one contact action that takes an email address as a parameter.
As a result,
ContactForm.contact("test#gmail.com").delivers #=> delivers email perfectly
But that's working on the command line. I don't really know the correct way to do this with a link. I mean, I could create a button that naviagates to send_email, and then I could have a route like this:
get 'send_email', to: 'contact#sendemail'
Then I would have a sendemail action which contains this method chain as shown above.
But this isn't asynchronous, and, also, I have no idea how I could validate the email's fields before sending the email, or highlighting invalid fields.
Is Ajax and JSON responses the key to highlighting the fields? What about the validation?
The resque_mailer seems to be a good way to send asyncronous emails. But why do I need this external gem when ajax is handled so well by vanilla rails?
The concept would be to have the form submit remotely. i.e submit to a create method in ContactsController. The method would then call a worker (resque/sidekiq) to send the email.
The create action can also respond to json. The json, response can either be a success or a fail (with errors).
On the AJAX success callback, you can trigger an alert, display div, or whatever notifying the user that the email was sent.
If the json results are returned with erros, then you can display the error message via JS.
This Railscasts Episode #171 Demonstrates sending emails using a background process with the help of DelayedJob

Resources