Skip to content

Commit

Permalink
Add content_type and size errors to base attribute
Browse files Browse the repository at this point in the history
This propagates attachment size and content_type validations to the main
attachment attribute, to make them behave the same as presence
validations. This allows paperclip to play more nicely with simple_form
and other form abstraction gems.

This commit includes a behaviorial change. If you emit all errors on a
model instance you will see some failed validations twice: once for the
base attachment attribute and again for the failed presence,
content_type or size attachment attributes.
  • Loading branch information
djcp authored and Jon Yurek committed Jun 21, 2013
1 parent edea587 commit 2aeb491
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 12 deletions.
16 changes: 9 additions & 7 deletions lib/paperclip/validators/attachment_content_type_validator.rb
Expand Up @@ -7,29 +7,31 @@ def initialize(options)
end

def validate_each(record, attribute, value)
base_attribute = attribute.to_sym
attribute = "#{attribute}_content_type".to_sym
value = record.send :read_attribute_for_validation, attribute

return if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])

validate_whitelist(record, attribute, value)
validate_blacklist(record, attribute, value)
validate_whitelist(record, base_attribute, attribute, value)
validate_blacklist(record, base_attribute, attribute, value)
end

def validate_whitelist(record, attribute, value)
def validate_whitelist(record, base_attribute, attribute, value)
if allowed_types.present? && allowed_types.none? { |type| type === value }
mark_invalid record, attribute, allowed_types
mark_invalid record, base_attribute, attribute, allowed_types
end
end

def validate_blacklist(record, attribute, value)
def validate_blacklist(record, base_attribute, attribute, value)
if forbidden_types.present? && forbidden_types.any? { |type| type === value }
mark_invalid record, attribute, forbidden_types
mark_invalid record, base_attribute, attribute, forbidden_types
end
end

def mark_invalid(record, attribute, types)
def mark_invalid(record, base_attribute, attribute, types)
record.errors.add attribute, :invalid, options.merge(:types => types.join(', '))
record.errors.add base_attribute, :invalid, options.merge(:types => types.join(', '))
end

def allowed_types
Expand Down
13 changes: 8 additions & 5 deletions lib/paperclip/validators/attachment_size_validator.rb
Expand Up @@ -11,6 +11,7 @@ def initialize(options)
end

def validate_each(record, attr_name, value)
base_attr_name = attr_name
attr_name = "#{attr_name}_file_size".to_sym
value = record.send(:read_attribute_for_validation, attr_name)

Expand All @@ -21,11 +22,13 @@ def validate_each(record, attr_name, value)

unless value.send(CHECKS[option], option_value)
error_message_key = options[:in] ? :in_between : option
record.errors.add(attr_name, error_message_key, filtered_options(value).merge(
:min => min_value_in_human_size(record),
:max => max_value_in_human_size(record),
:count => human_size(option_value)
))
[ attr_name, base_attr_name ].each do |error_attr_name|
record.errors.add(error_attr_name, error_message_key, filtered_options(value).merge(
:min => min_value_in_human_size(record),
:max => max_value_in_human_size(record),
:count => human_size(option_value)
))
end
end
end
end
Expand Down
26 changes: 26 additions & 0 deletions test/validators/attachment_content_type_validator_test.rb
Expand Up @@ -50,6 +50,32 @@ def build_validator(options)
end
end

context "with a failing validation" do
setup do
build_validator :content_type => "image/png", :allow_nil => false
@dummy.stubs(:avatar_content_type => nil)
@validator.validate(@dummy)
end

should "add error to the base object" do
assert @dummy.errors[:avatar].present?,
"Error not added to base attribute"
end
end

context "with a successful validation" do
setup do
build_validator :content_type => "image/png", :allow_nil => false
@dummy.stubs(:avatar_content_type => "image/png")
@validator.validate(@dummy)
end

should "not add error to the base object" do
assert @dummy.errors[:avatar].blank?,
"Error was added to base attribute"
end
end

context "with :allow_blank option" do
context "as true" do
setup do
Expand Down
10 changes: 10 additions & 0 deletions test/validators/attachment_size_validator_test.rb
Expand Up @@ -20,6 +20,11 @@ def self.should_allow_attachment_file_size(size)
assert @dummy.errors[:avatar_file_size].blank?,
"Expect an error message on :avatar_file_size, got none."
end

should "not add error to the base dummy object" do
assert @dummy.errors[:avatar].blank?,
"Error added to base attribute"
end
end
end

Expand All @@ -35,6 +40,11 @@ def self.should_not_allow_attachment_file_size(size, options = {})
"Unexpected error message on :avatar_file_size"
end

should "add error to the base dummy object" do
assert @dummy.errors[:avatar].present?,
"Error not added to base attribute"
end

if options[:message]
should "return a correct error message" do
assert_includes @dummy.errors[:avatar_file_size], options[:message]
Expand Down

0 comments on commit 2aeb491

Please sign in to comment.