markevans/dragonfly — Issue #135: Intermittent validation errors with Rails 3.1.0
Author: malclocke
Created: 2011-10-14 04:07:20+00:00
State: open

Hi,

Rails 3.1.0
Dragonfly `5e953f803f90f9e1963c795c1baa94a0b9156746`

I'm trying to backtrack to get a solution to this, but it's proving very elusive as I haven't yet come up with a guaranteed method of reproduction. Am starting this ticket here in case anyone can shed any light on where I might look for extra clues.

We're running a Rails 3.1.0 app, with multiple models having multiple image fields using Dragonfly. We have `validates_property` for all of the images, checking width and height. Occasionally, a validation will fail because the `attachment.width` and or `attachment.height` checks return bad values.

The only way I can reproduce this is by running our test suite in a loop and waiting for a failure. The failure points are seemingly completely random.

Here's an example model:

```ruby
# Imageable consts are just integers
class Design < ActiveRecord::Base

image_accessor :image
image_accessor :thumbnail_image

validates_property :width,
:of => :image,
:in => (Imageable::MinimumPixels..Imageable::MaximumPixels),
:message => :image_width_invalid

validates_property :height,
:of => :image,
:in => (Imageable::MinimumPixels..Imageable::MaximumPixels),
:message => :image_height_invalid

validates_property :format,
:of => :image,
:in => Imageable::ValidFormats,
:message => :image_format_invalid

validates_property :width,
:of => :thumbnail_image,
:as => Imageable::ThumbnailWidth,
:message => :image_width_invalid

validates_property :height,
:of => :thumbnail_image,
:as => Imageable::ThumbnailHeight,
:message => :image_height_invalid

validates_property :format,
:of => :thumbnail_image,
:in => Imageable::ValidFormats,
:message => :image_format_invalid

end

```

So far, I've added the following debug:

```diff
diff --git a/lib/dragonfly/active_model_extensions/validations.rb b/lib/dragonfly/active_model_extensions/validations.rb
index 236100e..8f3ccd1 100644
--- a/lib/dragonfly/active_model_extensions/validations.rb
+++ b/lib/dragonfly/active_model_extensions/validations.rb
@@ -16,6 +16,12 @@ module Dragonfly
if attachment
property = attachment.send(property_name)
unless allowed_values.include?(property)
+ puts "Validation failed for #{model}##{attr}##{property_name}"
+ puts "-> got #{property}: wanted: #{allowed_values.inspect}"
+ puts "-> attachment model: #{attachment.instance_variable_get('@model')}"
+ puts "-> meta: #{attachment.meta.inspect}"
+ puts "-> width: #{attachment.width} height: #{attachment.height}"
+ puts attachment.inspect
message = opts[:message] ||
"#{property_name.to_s.humanize.downcase} is incorrect. "+
"It needs to be #{Validations.expected_values_string(allowed_values)}"+
```

and on the test failure I get this. The image `1600x1200_152k.jpg` is the one expected on the model object in the test, but the value being returned for `width` and `height` (200px) is clearly wrong, and is coming from one of the other images.

I'd appreciate any pointers to potential candidates that might be causing this, it's taking me a while to unpick the code path in the gem.

```Validation failed for Design 3#image#width
-> got 200: wanted: 1000..5000
-> attachment model: Design 3
-> meta: {:name=>"1600x1200_152k.jpg", :model_class=>"Design", :model_attachment=>:image}
-> width: 200 height: 200
, @encoder=#, @processor=#, @analyser=#, @child_configurables=[#, #, #, #, #, @log_object=#, @config_methods=[:allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve], @fallback_configurable=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @child_configurables=[], @default_configuration={:allow_fetch_file=>false, :allow_fetch_url=>false, :dragonfly_url=>"/dragonfly", :protect_from_dos_attacks=>false, :url_format=>"/:job/:basename.:format", :url_host=>nil}, @url_mapper=#, #, #], @url_regexp=/^\/media(\/[\w+~]+?)?(\/[^\/]+?)?(\.[^\.]+?)?$/, @params_in_url=["job", "basename", "format"]>>], @config_methods=[:datastore, :datastore=, :cache_duration, :cache_duration=, :fallback_mime_type, :fallback_mime_type=, :secret, :secret=, :log, :log=, :trust_file_extensions, :trust_file_extensions=, :content_disposition, :content_disposition=, :content_filename, :content_filename=, :job, :register_mime_type, :response_headers, :define_url, :url_path_prefix=, :url_suffix=, :infer_mime_type_from_file_ext=, :allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve, :convert_command, :convert_command=, :identify_command, :identify_command=, :log_commands, :log_commands=, :supported_formats, :supported_formats=, :file_command, :file_command=, :use_filesystem, :use_filesystem=, :num_bytes_to_check, :num_bytes_to_check=], @server=#, @log_object=#, @config_methods=[:allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve], @fallback_configurable=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @child_configurables=[], @default_configuration={:allow_fetch_file=>false, :allow_fetch_url=>false, :dragonfly_url=>"/dragonfly", :protect_from_dos_attacks=>false, :url_format=>"/:job/:basename.:format", :url_host=>nil}, @url_mapper=#, #, #], @url_regexp=/^\/media(\/[\w+~]+?)?(\/[^\/]+?)?(\.[^\.]+?)?$/, @params_in_url=["job", "basename", "format"]>>, @job_definitions=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @default_configuration={:datastore=>#"/home/malc/clients/shuttlerock/shuttlerock/public/system/dragonfly/test", :server_root=>"/home/malc/clients/shuttlerock/shuttlerock/public"}, @child_configurables=[], @server_root="/home/malc/clients/shuttlerock/shuttlerock/public", @default_configuration={:root_path=>"/var/tmp/dragonfly", :server_root=>nil, :store_meta=>true}>, :cache_duration=>31536000, :fallback_mime_type=>"application/octet-stream", :secret=>"secret yo", :log=>#>, :trust_file_extensions=>true, :content_disposition=>nil, :content_filename=>#}, @job_class=#>>
Validation failed for Design 3#image#height
-> got 200: wanted: 1000..5000
-> attachment model: Design 3
-> meta: {:name=>"1600x1200_152k.jpg", :model_class=>"Design", :model_attachment=>:image}
-> width: 200 height: 200
, @encoder=#, @processor=#, @analyser=#, @child_configurables=[#, #, #, #, #, @log_object=#, @config_methods=[:allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve], @fallback_configurable=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @child_configurables=[], @default_configuration={:allow_fetch_file=>false, :allow_fetch_url=>false, :dragonfly_url=>"/dragonfly", :protect_from_dos_attacks=>false, :url_format=>"/:job/:basename.:format", :url_host=>nil}, @url_mapper=#, #, #], @url_regexp=/^\/media(\/[\w+~]+?)?(\/[^\/]+?)?(\.[^\.]+?)?$/, @params_in_url=["job", "basename", "format"]>>], @config_methods=[:datastore, :datastore=, :cache_duration, :cache_duration=, :fallback_mime_type, :fallback_mime_type=, :secret, :secret=, :log, :log=, :trust_file_extensions, :trust_file_extensions=, :content_disposition, :content_disposition=, :content_filename, :content_filename=, :job, :register_mime_type, :response_headers, :define_url, :url_path_prefix=, :url_suffix=, :infer_mime_type_from_file_ext=, :allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve, :convert_command, :convert_command=, :identify_command, :identify_command=, :log_commands, :log_commands=, :supported_formats, :supported_formats=, :file_command, :file_command=, :use_filesystem, :use_filesystem=, :num_bytes_to_check, :num_bytes_to_check=], @server=#, @log_object=#, @config_methods=[:allow_fetch_file, :allow_fetch_file=, :allow_fetch_url, :allow_fetch_url=, :dragonfly_url, :dragonfly_url=, :protect_from_dos_attacks, :protect_from_dos_attacks=, :url_format, :url_format=, :url_host, :url_host=, :before_serve], @fallback_configurable=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @child_configurables=[], @default_configuration={:allow_fetch_file=>false, :allow_fetch_url=>false, :dragonfly_url=>"/dragonfly", :protect_from_dos_attacks=>false, :url_format=>"/:job/:basename.:format", :url_host=>nil}, @url_mapper=#, #, #], @url_regexp=/^\/media(\/[\w+~]+?)?(\/[^\/]+?)?(\.[^\.]+?)?$/, @params_in_url=["job", "basename", "format"]>>, @job_definitions=#, @configuration={:log=>#, @log=#>, :url_format=>"/media/:job/:basename.:format", :log_commands=>true}, @default_configuration={:datastore=>#"/home/malc/clients/shuttlerock/shuttlerock/public/system/dragonfly/test", :server_root=>"/home/malc/clients/shuttlerock/shuttlerock/public"}, @child_configurables=[], @server_root="/home/malc/clients/shuttlerock/shuttlerock/public", @default_configuration={:root_path=>"/var/tmp/dragonfly", :server_root=>nil, :store_meta=>true}>, :cache_duration=>31536000, :fallback_mime_type=>"application/octet-stream", :secret=>"secret yo", :log=>#>, :trust_file_extensions=>true, :content_disposition=>nil, :content_filename=>#}, @job_class=#>>
```