Question

I will add a honeypot-field to the devise registration form (as a simple captcha). Where is the best place to check if data has been entered into this field?

If a bot has entered something into this field, he should be sent back to the index page without notification. As I am still far from being fluent in Rails, it would be helpful to see the syntax for this too.

Was it helpful?

Solution

I think the best place to do that is at the model, because it may be a business logic to accept only records from "verified humans".

You can create a validation method that does this:

class Comment < ActiveRecord::Base
  validate :honeypot_absence

  def honeypot_absence
    record.errors.add :invisible_field, "You should not fill the invisible field" unless invisible.field.blank?
  end
end

OTHER TIPS

I had a similar issue with bots signing up via my Devise registration form so tackled it by doing the following:

  1. Added a simple honeypot input to the view. (You will have needed to generate the views before you can do this - rails generate devise:views)
# app/views/devise/registrations/new.html.erb

<div class="form__honeypot">
  If you see this, leave it blank. Only bots should see this
  <input type="text" name="body" value="" />
</div>
  1. Hid the field using CSS.
.form {
  position: relative;

  &__honeypot {
    position: absolute;
    visibility: hidden;
    left: -5000px;
    top: -5000px;
  }
}
  1. Generate the Devise controllers so you can tap into the create method.

rails g devise:controllers users -c=registrations

You can generate them all or just the one you need using the -c flag.

  1. In the newly generated controller, added the following code:
# app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  before_action :configure_sign_up_params, only: [:create]

  def create
    if params[:body].present?
      return redirect_to root_path
    end
    super
  end

  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [:body])
  end
end

Essentially this is going to redirect anyone (hopefully bots), who populate the hidden field on the form, back to the root_url

  1. Finally in the routes.rb, added the line let Devise know to use our generated controller to handle registrations.
# config/routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: { registrations: 'users/registrations' }
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top