diff --git a/lib/paperclip.rb b/lib/paperclip.rb index 7d2458161..e2831a6b7 100644 --- a/lib/paperclip.rb +++ b/lib/paperclip.rb @@ -195,23 +195,6 @@ def has_attached_file(name, options = {}) end end - # Places ActiveRecord-style validations on the presence of a file. - # Options: - # * +if+: A lambda or name of an instance method. Validation will only - # be run if this lambda or method returns true. - # * +unless+: Same as +if+ but validates if lambda or method returns false. - def validates_attachment_presence name, options = {} - message = options[:message] || :empty - validates_each :"#{name}_file_name" do |record, attr, value| - if_clause_passed = options[:if].nil? || (options[:if].respond_to?(:call) ? options[:if].call(record) != false : record.send(options[:if])) - unless_clause_passed = options[:unless].nil? || (options[:unless].respond_to?(:call) ? !!options[:unless].call(record) == false : !record.send(options[:unless])) - if if_clause_passed && unless_clause_passed && value.blank? - record.errors.add(name, message) - record.errors.add("#{name}_file_name", message) - end - end - end - # Places ActiveRecord-style validations on the content type of the file # assigned. The possible options are: # * +content_type+: Allowed content types. Can be a single content type diff --git a/lib/paperclip/validators.rb b/lib/paperclip/validators.rb index bcc42449a..367a928c8 100644 --- a/lib/paperclip/validators.rb +++ b/lib/paperclip/validators.rb @@ -1,4 +1,5 @@ require 'active_support/concern' +require 'paperclip/validators/attachment_presence_validator' require 'paperclip/validators/attachment_size_validator' module Paperclip diff --git a/lib/paperclip/validators/attachment_presence_validator.rb b/lib/paperclip/validators/attachment_presence_validator.rb new file mode 100644 index 000000000..61ec7b9e1 --- /dev/null +++ b/lib/paperclip/validators/attachment_presence_validator.rb @@ -0,0 +1,26 @@ +require 'active_model/validations/presence' + +module Paperclip + module Validators + class AttachmentPresenceValidator < ActiveModel::Validations::PresenceValidator + def validate(record) + [attributes].flatten.map do |attribute| + if record.send(:read_attribute_for_validation, "#{attribute}_file_name").blank? + record.errors.add(attribute, :blank, options) + end + end + end + end + + module HelperMethods + # Places ActiveRecord-style validations on the presence of a file. + # Options: + # * +if+: A lambda or name of an instance method. Validation will only + # be run if this lambda or method returns true. + # * +unless+: Same as +if+ but validates if lambda or method returns false. + def validates_attachment_presence(*attr_names) + validates_with AttachmentPresenceValidator, _merge_attributes(attr_names) + end + end + end +end diff --git a/test/validators/attachment_presence_validator_test.rb b/test/validators/attachment_presence_validator_test.rb new file mode 100644 index 000000000..9ae930459 --- /dev/null +++ b/test/validators/attachment_presence_validator_test.rb @@ -0,0 +1,85 @@ +require './test/helper' + +class AttachmentPresenceValidatorTest < Test::Unit::TestCase + def setup + rebuild_model + @dummy = Dummy.new + end + + def build_validator(options={}) + @validator = Paperclip::Validators::AttachmentPresenceValidator.new(options.merge( + :attributes => :avatar + )) + end + + context "nil attachment" do + setup do + @dummy.avatar = nil + end + + context "with default options" do + setup do + build_validator + @validator.validate(@dummy) + end + + should "add error on the attachment" do + assert @dummy.errors[:avatar].present? + end + + should "not add an error on the file_name attribute" do + assert @dummy.errors[:avatar_file_name].blank? + end + end + + context "with :if option" do + context "returning true" do + setup do + build_validator :if => true + @validator.validate(@dummy) + end + + should "perform a validation" do + assert @dummy.errors[:avatar].present? + end + end + + context "returning false" do + setup do + build_validator :if => false + @validator.validate(@dummy) + end + + should "perform a validation" do + assert @dummy.errors[:avatar].present? + end + end + end + end + + context "with attachment" do + setup do + build_validator + @dummy.avatar = StringIO.new('.') + @validator.validate(@dummy) + end + + should "not add error on the attachment" do + assert @dummy.errors[:avatar].blank? + end + + should "not add an error on the file_name attribute" do + assert @dummy.errors[:avatar_file_name].blank? + end + end + + context "using the helper" do + setup do + Dummy.validates_attachment_presence :avatar + end + + should "add the validator to the class" do + assert Dummy.validators_on(:avatar).any?{ |validator| validator.kind == :attachment_presence } + end + end +end