Module: FastSubmissionProtection::Controller::ClassMethods

Defined in:
lib/fast_submission_protection/controller.rb

Instance Method Summary collapse

Instance Method Details

#protect_from_fast_submission(options = {}) ⇒ Object

protects a create action from fast_submission

This checks the time taken between the form being rendered (by new, or failed create), and the form being posted to the create action. If it is less than the specified time, an error is raised, which is rescued with a basic 420 error page (enhance your calm) which invites the user to click their back button, wait 5 seconds, and try again.

Options:

* :name:    The name of the submission (default "#{controller_name}_create")
* :delay:   The time to wait (default 5 seconds)
* :start:   List of actions when the timer should be started (default [:new, :create])
* :finish:  List of actions when the timer should be finished (default [:create])
* :rescue:  Rescue SubmissionTooFast error with a 420.html error page (default true)

If your submission starts in one controller and finishes in another, you can start the timer wherever you like, as follows

# At the class level, ie specifying a filter where the submission ends
before_filter FastSubmissionProtection::FinishFilter.new('abused_form_post'), :only => [:create]
# and where the submission starts
before_filter FastSubmissionProtection::StartFilter.new('abused_form_post'), :only => [:new]

# At the instance level, wherever you want, perhaps in an action
submission_timer('often_abused_form_post').start # to start

# later, somewhere else
submission_timer('often_abused_form_post').finish # to finsih, raises SubmissionTooFastError if too fast


33
34
35
36
37
38
39
40
41
42
43
# File 'lib/fast_submission_protection/controller.rb', line 33

def protect_from_fast_submission options = {}
  delay  = options[:delay]
  start  = options[:start] || [:new, :create]
  finish = options[:finish] || [:create]
  name   = options[:name] || "#{controller_name}_#{Array(finish).join('_')}"

  include Rescue unless options[:rescue] == false || self < Rescue

  before_filter FinishFilter.new(name, delay), :only => finish
  before_filter StartFilter.new(name), :only => start
end