validates_captcha 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.9.6 (October 30, 2009)
2
+
3
+ * Do not make captcha_challenge and captcha_solution attr_accessible. Instead overwrite AR#attributes= so they can be mass assigned.
4
+
5
+
1
6
  == 0.9.5 (October 9, 2009)
2
7
 
3
8
  * API change: renamed Provider::Image to Provider::DynamicImage in order to guard against confusion
@@ -20,3 +25,4 @@
20
25
  == 0.9.2 (September 27, 2009)
21
26
 
22
27
  * Initial version
28
+
data/Rakefile CHANGED
@@ -29,10 +29,10 @@ Rake::RDocTask.new do |rdoc|
29
29
  rdoc.rdoc_dir = 'doc'
30
30
  rdoc.title = "Validates Captcha"
31
31
  rdoc.main = "README.rdoc"
32
-
32
+
33
33
  rdoc.options << '--line-numbers' << '--inline-source'
34
34
  rdoc.options << '--charset' << 'utf-8'
35
-
35
+
36
36
  rdoc.rdoc_files.include 'README.rdoc'
37
37
  rdoc.rdoc_files.include 'MIT-LICENSE'
38
38
  rdoc.rdoc_files.include 'CHANGELOG.rdoc'
@@ -52,18 +52,18 @@ end
52
52
 
53
53
  desc 'Run tests by default'
54
54
  task :default => :test
55
-
55
+
56
56
  Rake::TestTask.new do |t|
57
57
  t.libs << 'test'
58
58
  t.test_files = FileList['test/**/*_test.rb']
59
59
  #t.verbose = true
60
60
  #t.warning = true
61
61
  end
62
-
63
-
64
-
62
+
63
+
64
+
65
65
  spec = eval(File.read('validates_captcha.gemspec'))
66
-
66
+
67
67
  Rake::GemPackageTask.new(spec) do |pkg|
68
68
  pkg.gem_spec = spec
69
69
  pkg.need_tar = true
@@ -76,9 +76,9 @@ desc 'Publish the release files to RubyForge'
76
76
  task :release => [:package] do
77
77
  require 'rubyforge'
78
78
  require 'rake/contrib/rubyforgepublisher'
79
-
79
+
80
80
  packages = %w(gem tgz zip).collect { |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
81
-
81
+
82
82
  rubyforge = RubyForge.new
83
83
  rubyforge.configure
84
84
  rubyforge.add_release RUBY_FORGE_PROJECT, RUBY_FORGE_PROJECT, RELEASE_NAME, *packages
@@ -22,10 +22,10 @@
22
22
  #++
23
23
 
24
24
 
25
- # This module contains the getter and setter for the captcha provider.
26
- # This allows you to replace it with your custom implementation. For more
27
- # information on how to bring Validates Captcha to use your own
28
- # implementation instead of the default one, consult the documentation
25
+ # This module contains the getter and setter for the captcha provider.
26
+ # This allows you to replace it with your custom implementation. For more
27
+ # information on how to bring Validates Captcha to use your own
28
+ # implementation instead of the default one, consult the documentation
29
29
  # for the default provider.
30
30
  module ValidatesCaptcha
31
31
  autoload :ModelValidation, 'validates_captcha/model_validation'
@@ -34,34 +34,34 @@ module ValidatesCaptcha
34
34
  autoload :FormBuilder, 'validates_captcha/form_builder'
35
35
  autoload :TestCase, 'validates_captcha/test_case'
36
36
  autoload :VERSION, 'validates_captcha/version'
37
-
37
+
38
38
  module Provider
39
39
  autoload :Question, 'validates_captcha/provider/question'
40
40
  autoload :DynamicImage, 'validates_captcha/provider/dynamic_image'
41
41
  autoload :StaticImage, 'validates_captcha/provider/static_image'
42
42
  end
43
-
43
+
44
44
  module StringGenerator
45
45
  autoload :Simple, 'validates_captcha/string_generator/simple'
46
46
  end
47
-
47
+
48
48
  module SymmetricEncryptor
49
49
  autoload :Simple, 'validates_captcha/symmetric_encryptor/simple'
50
50
  end
51
-
51
+
52
52
  module ImageGenerator
53
53
  autoload :Simple, 'validates_captcha/image_generator/simple'
54
54
  end
55
-
55
+
56
56
  @@provider = nil
57
-
57
+
58
58
  class << self
59
59
  # Returns Validates Captcha's current version number.
60
60
  def version
61
61
  ValidatesCaptcha::VERSION::STRING
62
62
  end
63
-
64
- # Returns the current captcha challenge provider. Defaults to an instance of
63
+
64
+ # Returns the current captcha challenge provider. Defaults to an instance of
65
65
  # the ValidatesCaptcha::Provider::Question class.
66
66
  def provider
67
67
  @@provider ||= Provider::Question.new
@@ -3,12 +3,12 @@ module ValidatesCaptcha
3
3
  def self.included(base) #:nodoc:
4
4
  base.extend ClassMethods
5
5
  end
6
-
7
- # This module extends ActionController::Base with methods for captcha
6
+
7
+ # This module extends ActionController::Base with methods for captcha
8
8
  # verification.
9
- module ClassMethods
10
- # This method is the one Validates Captcha got its name from. It
11
- # internally calls #validates_captcha_of with the name of the controller
9
+ module ClassMethods
10
+ # This method is the one Validates Captcha got its name from. It
11
+ # internally calls #validates_captcha_of with the name of the controller
12
12
  # as first argument and passing the conditions hash.
13
13
  #
14
14
  # Usage Example:
@@ -26,13 +26,13 @@ module ValidatesCaptcha
26
26
  def validates_captcha(conditions = {})
27
27
  validates_captcha_of controller_name, conditions
28
28
  end
29
-
29
+
30
30
  # Activates captcha validation for the specified model.
31
31
  #
32
32
  # The +model+ argument can be a Class, a string, or a symbol.
33
33
  #
34
- # This method internally creates an around filter, passing the
35
- # +conditions+ argument to it. So you can (de)activate captcha
34
+ # This method internally creates an around filter, passing the
35
+ # +conditions+ argument to it. So you can (de)activate captcha
36
36
  # validation for specific actions.
37
37
  #
38
38
  # Usage examples:
@@ -43,11 +43,11 @@ module ValidatesCaptcha
43
43
  # validates_captcha_of 'user', :except => :persist
44
44
  #
45
45
  # # ... actions go here ...
46
- # end
46
+ # end
47
47
  def validates_captcha_of(model, conditions = {})
48
48
  model = model.is_a?(Class) ? model : model.to_s.classify.constantize
49
49
  without_formats = Array.wrap(conditions.delete(:without)).map(&:to_sym)
50
-
50
+
51
51
  around_filter(conditions) do |controller, action|
52
52
  if without_formats.include?(controller.request.format.to_sym)
53
53
  action.call
@@ -61,3 +61,4 @@ module ValidatesCaptcha
61
61
  end
62
62
  end
63
63
  end
64
+
@@ -3,11 +3,11 @@ module ValidatesCaptcha
3
3
  def captcha_challenge(options = {}) #:nodoc:
4
4
  @template.captcha_challenge @object_name, options.merge(:object => @object)
5
5
  end
6
-
6
+
7
7
  def captcha_field(options = {}) #:nodoc:
8
8
  @template.captcha_field @object_name, options.merge(:object => @object)
9
9
  end
10
-
10
+
11
11
  def regenerate_captcha_challenge_link(options = {}, html_options = {}) #:nodoc:
12
12
  @template.regenerate_captcha_challenge_link @object_name, options.merge(:object => @object), html_options
13
13
  end
@@ -1,37 +1,37 @@
1
1
  module ValidatesCaptcha
2
2
  module FormHelper
3
- # Returns the captcha challenge.
3
+ # Returns the captcha challenge.
4
4
  #
5
5
  # Internally calls the +render_challenge+ method of ValidatesCaptcha#provider.
6
6
  def captcha_challenge(object_name, options = {})
7
7
  options.symbolize_keys!
8
-
8
+
9
9
  object = options.delete(:object)
10
10
  sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
11
-
11
+
12
12
  ValidatesCaptcha.provider.render_challenge sanitized_object_name, object, options
13
13
  end
14
-
14
+
15
15
  # Returns an input tag of the "text" type tailored for entering the captcha solution.
16
16
  #
17
- # Internally calls Rails' #text_field helper method, passing the +object_name+ and
17
+ # Internally calls Rails' #text_field helper method, passing the +object_name+ and
18
18
  # +options+ arguments.
19
19
  def captcha_field(object_name, options = {})
20
20
  options.delete(:id)
21
-
21
+
22
22
  hidden_field(object_name, :captcha_challenge, options) + text_field(object_name, :captcha_solution, options)
23
23
  end
24
-
25
- # By default, returns an anchor tag that makes an AJAX request to fetch a new captcha challenge and updates
24
+
25
+ # By default, returns an anchor tag that makes an AJAX request to fetch a new captcha challenge and updates
26
26
  # the current challenge after the request is complete.
27
- #
27
+ #
28
28
  # Internally calls +render_regenerate_challenge_link+ method of ValidatesCaptcha#provider.
29
29
  def regenerate_captcha_challenge_link(object_name, options = {}, html_options = {})
30
30
  options.symbolize_keys!
31
-
31
+
32
32
  object = options.delete(:object)
33
33
  sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
34
-
34
+
35
35
  ValidatesCaptcha.provider.render_regenerate_challenge_link sanitized_object_name, object, options, html_options
36
36
  end
37
37
  end
@@ -1,24 +1,24 @@
1
1
  module ValidatesCaptcha
2
2
  module ImageGenerator
3
- # This class is responsible for creating the captcha image. It internally
4
- # uses ImageMagick's +convert+ command to generate the image bytes. So
3
+ # This class is responsible for creating the captcha image. It internally
4
+ # uses ImageMagick's +convert+ command to generate the image bytes. So
5
5
  # ImageMagick must be installed on the system for it to work properly.
6
6
  #
7
- # In order to deliver the captcha image to the user's browser,
8
- # Validate Captcha's Rack middleware calls the methods of this class
9
- # to create the image, to retrieve its mime type, and to construct the
7
+ # In order to deliver the captcha image to the user's browser,
8
+ # Validate Captcha's Rack middleware calls the methods of this class
9
+ # to create the image, to retrieve its mime type, and to construct the
10
10
  # path to it.
11
11
  #
12
- # The image generation process is no rocket science. The chars are just
13
- # laid out next to each other with varying vertical positions, font sizes,
14
- # and weights. Then a slight rotation is performed and some randomly
12
+ # The image generation process is no rocket science. The chars are just
13
+ # laid out next to each other with varying vertical positions, font sizes,
14
+ # and weights. Then a slight rotation is performed and some randomly
15
15
  # positioned lines are rendered on the canvas.
16
16
  #
17
- # Sure, the created captcha can easily be cracked by intelligent
18
- # bots. As the name of the class suggests, it's rather a starting point
17
+ # Sure, the created captcha can easily be cracked by intelligent
18
+ # bots. As the name of the class suggests, it's rather a starting point
19
19
  # for your own implementations.
20
20
  #
21
- # You can implement your own (better) image generator by creating a
21
+ # You can implement your own (better) image generator by creating a
22
22
  # class that conforms to the method definitions of the example below.
23
23
  #
24
24
  # Example for a custom image generator:
@@ -48,43 +48,43 @@ module ValidatesCaptcha
48
48
  #
49
49
  # ValidatesCaptcha::Provider::StaticImage.image_generator = AdvancedImageGenerator.new
50
50
  # ValidatesCaptcha.provider = ValidatesCaptcha::Provider::StaticImage.new
51
- #
51
+ #
52
52
  class Simple
53
53
  MIME_TYPE = 'image/gif'.freeze
54
54
  FILE_EXTENSION = '.gif'.freeze
55
-
56
- # Returns a string containing the image bytes of the captcha.
55
+
56
+ # Returns a string containing the image bytes of the captcha.
57
57
  # As the only argument, the cleartext captcha text must be passed.
58
58
  def generate(captcha_code)
59
59
  image_width = captcha_code.length * 20 + 10
60
-
60
+
61
61
  cmd = []
62
62
  cmd << "convert -size #{image_width}x40 xc:grey84 -background grey84 -fill black "
63
-
63
+
64
64
  captcha_code.split(//).each_with_index do |char, i|
65
65
  cmd << " -pointsize #{rand(8) + 15} "
66
66
  cmd << " -weight #{rand(2) == 0 ? '4' : '8'}00 "
67
67
  cmd << " -draw 'text #{5 + 20 * i},#{rand(10) + 20} \"#{char}\"' "
68
68
  end
69
-
69
+
70
70
  cmd << " -rotate #{rand(2) == 0 ? '-' : ''}5 -fill grey40 "
71
-
71
+
72
72
  captcha_code.size.times do
73
73
  cmd << " -draw 'line #{rand(image_width)},0 #{rand(image_width)},60' "
74
74
  end
75
-
75
+
76
76
  cmd << " gif:-"
77
-
77
+
78
78
  image_magick_command = cmd.join
79
-
79
+
80
80
  `#{image_magick_command}`
81
81
  end
82
-
82
+
83
83
  # Returns the image mime type. This is always 'image/gif'.
84
84
  def mime_type
85
85
  MIME_TYPE
86
86
  end
87
-
87
+
88
88
  # Returns the image file extension. This is always '.gif'.
89
89
  def file_extension
90
90
  FILE_EXTENSION
@@ -92,3 +92,4 @@ module ValidatesCaptcha
92
92
  end
93
93
  end
94
94
  end
95
+
@@ -3,18 +3,19 @@ module ValidatesCaptcha
3
3
  def self.included(base) #:nodoc:
4
4
  base.extend ClassMethods
5
5
  base.send :include, InstanceMethods
6
-
6
+
7
7
  base.class_eval do
8
- attr_accessible :captcha_challenge, :captcha_solution
9
8
  attr_accessor :captcha_solution
10
9
  attr_writer :captcha_challenge
11
-
10
+
11
+ alias_method_chain :attributes=, :captcha_fields
12
+
12
13
  validate :validate_captcha, :if => :validate_captcha?
13
14
  end
14
15
  end
15
-
16
+
16
17
  module ClassMethods
17
- # Activates captcha validation on entering the block and deactivates
18
+ # Activates captcha validation on entering the block and deactivates
18
19
  # captcha validation on leaving the block.
19
20
  #
20
21
  # Example:
@@ -29,37 +30,52 @@ module ValidatesCaptcha
29
30
  self.validate_captcha = false
30
31
  result
31
32
  end
32
-
33
+
33
34
  # Returns +true+ if captcha validation is activated, otherwise +false+.
34
35
  def validate_captcha? #:nodoc:
35
36
  @validate_captcha == true
36
37
  end
37
-
38
+
38
39
  private
39
40
  def validate_captcha=(value) #:nodoc:
40
41
  @validate_captcha = value
41
42
  end
42
43
  end
43
-
44
+
44
45
  module InstanceMethods #:nodoc:
45
46
  def captcha_challenge #:nodoc:
46
47
  return @captcha_challenge unless @captcha_challenge.blank?
47
48
  @captcha_challenge = ValidatesCaptcha.provider.generate_challenge
48
49
  end
49
-
50
- private
50
+
51
+ def attributes_with_captcha_fields=(new_attributes, guard_protected_attributes = true)
52
+ if new_attributes && guard_protected_attributes &&
53
+ (new_attributes.key?('captcha_challenge') || new_attributes.key?(:captcha_challenge))
54
+ attributes = new_attributes.dup
55
+ attributes.stringify_keys!
56
+
57
+ self.captcha_challenge = attributes.delete('captcha_challenge')
58
+ self.captcha_solution = attributes.delete('captcha_solution')
59
+
60
+ new_attributes = attributes
61
+ end
62
+
63
+ send :attributes_without_captcha_fields=, new_attributes, guard_protected_attributes
64
+ end
65
+
66
+ private
51
67
  def validate_captcha? #:nodoc:
52
68
  self.class.validate_captcha?
53
69
  end
54
-
70
+
55
71
  def validate_captcha #:nodoc:
56
72
  errors.add(:captcha_solution, :blank) and return if captcha_solution.blank?
57
73
  errors.add(:captcha_solution, :invalid) unless captcha_valid?
58
74
  end
59
-
75
+
60
76
  def captcha_valid? #:nodoc:
61
77
  ValidatesCaptcha.provider.solved?(captcha_challenge, captcha_solution)
62
- end
78
+ end
63
79
  end
64
80
  end
65
81
  end
@@ -1,8 +1,8 @@
1
1
  require 'action_view/helpers'
2
2
 
3
3
  module ValidatesCaptcha
4
- # Here is how you can implement your own captcha challenge provider. Create a
5
- # class that conforms to the public method definitions of the example below
4
+ # Here is how you can implement your own captcha challenge provider. Create a
5
+ # class that conforms to the public method definitions of the example below
6
6
  # and assign an instance of it to ValidatesCaptcha#provider=.
7
7
  #
8
8
  # Example:
@@ -26,7 +26,7 @@ module ValidatesCaptcha
26
26
  #
27
27
  # def render_challenge(sanitized_object_name, object, options = {})
28
28
  # options[:id] = "#{sanitized_object_name}_captcha_question"
29
- #
29
+ #
30
30
  # content_tag :span, "What's the reverse of '#{object.captcha_challenge}'?", options
31
31
  # end
32
32
  #
@@ -36,7 +36,7 @@ module ValidatesCaptcha
36
36
  # "$('#{sanitized_object_name}_captcha_question').update(result.question); " \\
37
37
  # "$('#{sanitized_object_name}_captcha_challenge').value = result.challenge; " \\
38
38
  # "$('#{sanitized_object_name}_captcha_solution').value = '';"
39
- #
39
+ #
40
40
  # link_to_remote text, options.reverse_merge(:url => '/captchas/regenerate', :method => :get, :success => success), html_options
41
41
  # end
42
42
  #
@@ -44,7 +44,7 @@ module ValidatesCaptcha
44
44
  # if env['PATH_INFO'] == '/captchas/regenerate'
45
45
  # challenge = generate_challenge
46
46
  # json = { :question => "What's the reverse of '#{challenge}'?", :challenge => challenge }.to_json
47
- #
47
+ #
48
48
  # [200, { 'Content-Type' => 'application/json' }, [json]]
49
49
  # else
50
50
  # [404, { 'Content-Type' => 'text/html' }, ['Not Found']]
@@ -69,61 +69,61 @@ module ValidatesCaptcha
69
69
  # implementation instead of the default one, consult the documentation
70
70
  # for the specific default class.
71
71
  #
72
- # The default captcha image generator uses ImageMagick's +convert+ command to
73
- # create the captcha. So a recent and properly configured version of ImageMagick
74
- # must be installed on the system. The version used while developing was 6.4.5.
75
- # But you are not bound to ImageMagick. If you want to provide a custom image
76
- # generator, take a look at the documentation for
72
+ # The default captcha image generator uses ImageMagick's +convert+ command to
73
+ # create the captcha. So a recent and properly configured version of ImageMagick
74
+ # must be installed on the system. The version used while developing was 6.4.5.
75
+ # But you are not bound to ImageMagick. If you want to provide a custom image
76
+ # generator, take a look at the documentation for
77
77
  # ValidatesCaptcha::ImageGenerator::Simple on how to create your own.
78
78
  class DynamicImage
79
79
  include ActionView::Helpers
80
-
80
+
81
81
  @@string_generator = nil
82
82
  @@symmetric_encryptor = nil
83
83
  @@image_generator = nil
84
-
84
+
85
85
  class << self
86
86
  # Returns the current captcha string generator. Defaults to an
87
87
  # instance of the ValidatesCaptcha::StringGenerator::Simple class.
88
88
  def string_generator
89
89
  @@string_generator ||= ValidatesCaptcha::StringGenerator::Simple.new
90
90
  end
91
-
91
+
92
92
  # Sets the current captcha string generator. Used to set a
93
93
  # custom string generator.
94
94
  def string_generator=(generator)
95
95
  @@string_generator = generator
96
96
  end
97
-
97
+
98
98
  # Returns the current captcha symmetric encryptor. Defaults to an
99
99
  # instance of the ValidatesCaptcha::SymmetricEncryptor::Simple class.
100
100
  def symmetric_encryptor
101
101
  @@symmetric_encryptor ||= ValidatesCaptcha::SymmetricEncryptor::Simple.new
102
102
  end
103
-
103
+
104
104
  # Sets the current captcha symmetric encryptor. Used to set a
105
105
  # custom symmetric encryptor.
106
106
  def symmetric_encryptor=(encryptor)
107
107
  @@symmetric_encryptor = encryptor
108
108
  end
109
-
109
+
110
110
  # Returns the current captcha image generator. Defaults to an
111
111
  # instance of the ValidatesCaptcha::ImageGenerator::Simple class.
112
112
  def image_generator
113
113
  @@image_generator ||= ValidatesCaptcha::ImageGenerator::Simple.new
114
114
  end
115
-
115
+
116
116
  # Sets the current captcha image generator. Used to set a custom
117
117
  # image generator.
118
118
  def image_generator=(generator)
119
119
  @@image_generator = generator
120
120
  end
121
121
  end
122
-
122
+
123
123
  # This method is the one called by Rack.
124
- #
125
- # It returns HTTP status 404 if the path is not recognized. If the path is
126
- # recognized, it returns HTTP status 200 and delivers the image if it could
124
+ #
125
+ # It returns HTTP status 404 if the path is not recognized. If the path is
126
+ # recognized, it returns HTTP status 200 and delivers the image if it could
127
127
  # successfully decrypt the captcha code, otherwise HTTP status 422.
128
128
  #
129
129
  # Please take a look at the source code if you want to learn more.
@@ -132,16 +132,16 @@ module ValidatesCaptcha
132
132
  if $1 == 'regenerate'
133
133
  captcha_challenge = generate_challenge
134
134
  json = { :captcha_challenge => captcha_challenge, :captcha_image_path => image_path(captcha_challenge) }.to_json
135
-
135
+
136
136
  [200, { 'Content-Type' => 'application/json' }, [json]]
137
137
  else
138
138
  decrypted_code = decrypt($1)
139
-
139
+
140
140
  if decrypted_code.nil?
141
141
  [422, { 'Content-Type' => 'text/html' }, ['Unprocessable Entity']]
142
142
  else
143
143
  image_data = generate_image(decrypted_code)
144
-
144
+
145
145
  response_headers = {
146
146
  'Content-Length' => image_data.bytesize.to_s,
147
147
  'Content-Type' => image_mime_type,
@@ -149,7 +149,7 @@ module ValidatesCaptcha
149
149
  'Content-Transfer-Encoding' => 'binary',
150
150
  'Cache-Control' => 'private'
151
151
  }
152
-
152
+
153
153
  [200, response_headers, [image_data]]
154
154
  end
155
155
  end
@@ -157,79 +157,79 @@ module ValidatesCaptcha
157
157
  [404, { 'Content-Type' => 'text/html' }, ['Not Found']]
158
158
  end
159
159
  end
160
-
160
+
161
161
  # Returns a captcha challenge.
162
162
  def generate_challenge
163
163
  encrypt(generate_code)
164
164
  end
165
-
166
- # Returns true if the captcha was solved using the given +challenge+ and +solution+,
165
+
166
+ # Returns true if the captcha was solved using the given +challenge+ and +solution+,
167
167
  # otherwise false.
168
168
  def solved?(challenge, solution)
169
169
  decrypt(challenge) == solution
170
170
  end
171
-
171
+
172
172
  # Returns an image tag with the source set to the url of the captcha image.
173
- #
173
+ #
174
174
  # Internally calls Rails' +image_tag+ helper method, passing the +options+ argument.
175
175
  def render_challenge(sanitized_object_name, object, options = {})
176
176
  src = image_path(object.captcha_challenge)
177
-
177
+
178
178
  options[:alt] ||= 'CAPTCHA'
179
179
  options[:id] = "#{sanitized_object_name}_captcha_image"
180
-
180
+
181
181
  image_tag src, options
182
182
  end
183
-
184
- # Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates
183
+
184
+ # Returns an anchor tag that makes an AJAX request to fetch a new captcha code and updates
185
185
  # the captcha image after the request is complete.
186
- #
187
- # Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
188
- # +html_options+ arguments. So it relies on the Prototype javascript framework
186
+ #
187
+ # Internally calls Rails' +link_to_remote+ helper method, passing the +options+ and
188
+ # +html_options+ arguments. So it relies on the Prototype javascript framework
189
189
  # to be available on the web page.
190
190
  #
191
- # The anchor text defaults to 'Regenerate Captcha'. You can set this to a custom value
191
+ # The anchor text defaults to 'Regenerate Captcha'. You can set this to a custom value
192
192
  # providing a +:text+ key in the +options+ hash.
193
193
  def render_regenerate_challenge_link(sanitized_object_name, object, options = {}, html_options = {})
194
194
  text = options.delete(:text) || 'Regenerate Captcha'
195
195
  success = "var result = request.responseJSON; $('#{sanitized_object_name}_captcha_image').src = result.captcha_image_path; $('#{sanitized_object_name}_captcha_challenge').value = result.captcha_challenge; $('#{sanitized_object_name}_captcha_solution').value = '';"
196
-
196
+
197
197
  link_to_remote text, options.reverse_merge(:url => regenerate_path, :method => :get, :success => success), html_options
198
198
  end
199
-
200
- private
199
+
200
+ private
201
201
  def generate_image(code) #:nodoc:
202
202
  self.class.image_generator.generate code
203
203
  end
204
-
204
+
205
205
  def image_mime_type #:nodoc:
206
206
  self.class.image_generator.mime_type
207
207
  end
208
-
208
+
209
209
  def image_file_extension #:nodoc:
210
210
  self.class.image_generator.file_extension
211
211
  end
212
-
212
+
213
213
  def encrypt(code) #:nodoc:
214
214
  self.class.symmetric_encryptor.encrypt code
215
215
  end
216
-
216
+
217
217
  def decrypt(encrypted_code) #:nodoc:
218
218
  self.class.symmetric_encryptor.decrypt encrypted_code
219
219
  end
220
-
220
+
221
221
  def generate_code #:nodoc:
222
222
  self.class.string_generator.generate
223
223
  end
224
-
224
+
225
225
  def image_path(encrypted_code) #:nodoc:
226
226
  "/captchas/#{encrypted_code}#{image_file_extension}"
227
227
  end
228
-
228
+
229
229
  def regenerate_path #:nodoc:
230
230
  '/captchas/regenerate'
231
231
  end
232
-
232
+
233
233
  # This is needed by +link_to_remote+ called in +render_regenerate_link+.
234
234
  def protect_against_forgery? #:nodoc:
235
235
  false
@@ -237,4 +237,4 @@ module ValidatesCaptcha
237
237
  end
238
238
  end
239
239
  end
240
-
240
+