loading...

Adding reCaptcha v3 to a Rails app without a gem

Felice Forby on June 04, 2019

This article goes over how you can add Google reCaptcha v3 to a Rails app and use it to verify a form submission. I couldn't find any other how-to... [Read Full]
markdown guide
 

Did you run into any issues with Turbolinks doing it this way? I noticed the page with my form will only load the recaptcha if I refresh the page.

I tried wrapping the grecaptcha.ready function in a document.on(turbolinks:load) like this:

<script>
  $(document).on('turbolinks:load', function() {
      grecaptcha.ready(function() {
          grecaptcha.execute('#{ENV['RECAPTCHA_SITE_KEY']}', {action: '#{action}'}).then(function(token) {
            document.getElementById("#{id}").value = token;
          });
       });
   });
</script>

but to no avail. Any suggestions?

 

Hey Steven, I did not have any issues with turbolinks doing it the way I wrote in the blog post. I unfortunately haven't tried it with a document.on(turbolinks:load) wrapper.

 

Hey did you ever figure this out? Running into Uncaught ReferenceError: grecaptcha is not defined and it's referencing a lot of Turbolinks links.

 

Hey! Sorry for the late reply. It's been awhile but I think I ended up disabling turbolinks for that particular page and the code ran fine after that.

Check this out: github.com/turbolinks/turbolinks#d...

Hope that helps!

Ahh okay! I'll try that out, thank you so much!

 

Hi Felice, great article!

I'm handling my forms with ajax (remote: true) and I'm struggling to figure out how I can reset the recaptcha after a successful post. Any help would be appreciated :)

Thanks,
Ben

 

I know this is a little late but I just had to solve this problem so hopefully my response can help someone else. Basically, since my form is a create action, I edited my create.js file to update the token on failed submission. Here's how:

Here's a portion of my form where I render a partial that include my captcha tag:

...

<div class="col-12">
  <div class="form-group captcha captcha-lead_creation_modal">
    <%= render "potential_clients/captcha_field", action: 'lead_creation_modal' %>
  </div>
</div>

<div class="col-lg-12 d-flex m-t-20">
  <%= f.submit 'Request More Information', class: "btn btn-md btn-block btn-info-gradiant" %>
</div>

Here's the complete partial: potential_clients/captcha_field:

<%= recaptcha_execute(action) %>

Finally, in my create.js I do the following:

// other error handling / success code goes here

$(".captcha-lead_creation_modal").html("<%= j render 'potential_clients/captcha_field', action: 'lead_creation_modal' %>")

This will re-render the portion of the form with the token and since it hits the helper function, a new token is generated!

 

Nice! Thank you so much for sharing your solution!

 

Hi Ben, thanks for reading!

Unfortunately, I've never done the resetting with ajax myself, so I can't give you any tips from my own experience. I was just checking out some other blogs and the google documentation, though, and you might be able to use the reCaptcha javascript api and reset it with grecaptcha.reset(widgetId);. This blog post mentions it but not sure if it works.

 

First of all
thanks!! for helpful article for google reCaprcha v3 for rails..

I need some help to apply of this document...

rails version of my system is 4.1.11 ( because app which I use, can run under rails 4.xx only)

So I cannot use credentials.yml.enc file

Instead of credentials.yml.enc I should use another secret file (for example , secret_key_base )

But I do not know how to change the line to make the program work normally in ApplicationController.

I'm sorry, please teach me.

 

Hi there! Thank for reading!

Well, secrets from Rails' credential system are read with code that look like this (for example): Rails.application.credentials.dig(:recaptcha_secret_key). So, anywhere you see Rails.applications.credentials..., you need to replace it with how the other secret file like secret_key_base reads those variables. I'm not exactly sure how to do it for Rails 4 though, so you would need to research about that.

I have also used the dotenv gem before, which is very easy to use. You learn more about dotenv here. Basically, you make a file named .env and register any secret keys you need there. Then read them with something like ENV['SECRET_KEY'].

Hope that helps a little bit >< Sorry I don't know enough about the Rails 4 way to do it!

 

Anyone noticing recaptcha failures with this approach? the problem is a reCaptcha v3 will time out after 2 minutes, so if your users take longer to fill in the form the recaptcha json will return error-codes timeout-or-duplicate with a score of 0. It might be better to call recaptcha_execute on form submit to avoid this problem.

 

This article was really helpful so thanks for writing it up.

To address this comment, when I get back error-codes timeout-or-duplicate I am not receiving any score in that response (and success is false). I only get a score in the response when success is set to true, so I think the fact that he put json['success'] && json['score'] will address this correctly.

One thing I did was to add error handling with a begin/rescue in verify_recaptcha? because there are a couple things in that method that can blow up.

 

The following line makes a GET request, right? Shouldn't it be a POST?

Net::HTTP.get_response(uri)

I'm sorry if the question doesn't make sense, I'm a newbie, feeling a bit lost...
Thanks again for the amazing post, though, very easy to follow!

 

Hmm, it does look like the Google documentation says to make a POST request...

Honestly, when I wrote this (and still now), I had a really hard time understanding how the ReCaptcha worked, so I had to reference some other articles. Those articles all used Net::HTTP.get_response(uri) to get back the verification response.

You could try to make it a POST request instead and see how it works. I haven't tried it myself yet!

 

Great article as I found the google Docs extremely lacking on how to set this up for any site much less a Rails site. They make a lot of assumptions that you'll just get the part they're completely glossing over, e.g. the hidden field and token assignment.

One mistake I think I found though is in the method recaptcha_execute you have a reference to RECAPTCHA_SITE_KEY which I'm guessing is actually supposed to be ENV['RECAPTCHA_SITE_KEY'] or a defined constant. This might trip up some people. :)

 

Yikes, nice catch! It was supposed to be a constant above the two methods. Now fixed! Thanks for pointing that out.

I had a hard time with the Google documentation too, which is a big reason why I wrote this post! Thank you for reading :D

 

Top drawer Felice, thanks so much!

 
code of conduct - report abuse