diff --git a/app/models/account.rb b/app/models/account.rb index 98573cd..515f91f 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -6,14 +6,6 @@ class Account < ApplicationRecord NICKNAME_RE = /\A[a-z][_a-z0-9]*[a-z0-9]\z/.freeze - AVATAR_MAX_SIZE = 1.megabyte - - AVATAR_CONTENT_TYPES = %w[ - image/png - image/jpeg - image/gif - ].freeze - self.role_cname = 'Role' self.role_table_name = 'roles' self.strict_rolify = false @@ -76,8 +68,7 @@ class Account < ApplicationRecord validates :biography, allow_nil: true, length: { in: 3..10_000 } - validate :avatar_size_is_valid - validate :avatar_content_type_is_valid + validates :avatar, allow_nil: true, image: true ########### # Methods # @@ -137,18 +128,4 @@ private self.public_name = public_name&.strip self.biography = biography&.strip end - - def avatar_size_is_valid - return unless avatar.attached? - return if avatar.blob.byte_size <= AVATAR_MAX_SIZE - - errors.add :avatar, :size - end - - def avatar_content_type_is_valid - return unless avatar.attached? - return if avatar.blob.content_type.in? AVATAR_CONTENT_TYPES - - errors.add :avatar, :format, content_type: avatar.blob.content_type - end end diff --git a/app/validators/application_each_validator.rb b/app/validators/application_each_validator.rb new file mode 100644 index 0000000..0674309 --- /dev/null +++ b/app/validators/application_each_validator.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +class ApplicationEachValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + self.class::Validation.new(self, record, attribute, value).call + end + + class Validation + attr_reader :value + + delegate :options, to: :@validator + + def initialize(validator, record, attribute, value) + @validator = validator + @record = record + @attribute = attribute + @value = value + end + + def call + catch :stop_validating do + perform + end + end + + def perform + raise NotImplementedError, "#{self.class}#perform" + end + + def error(*args) + @record.errors.add @attribute, *args + end + + def error!(*args) + error(*args) + throw :stop_validating + end + end +end diff --git a/app/validators/image_validator.rb b/app/validators/image_validator.rb new file mode 100644 index 0000000..7389c99 --- /dev/null +++ b/app/validators/image_validator.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class ImageValidator < ApplicationEachValidator + class Validation < Validation + MAX_SIZE = 1.megabyte + + CONTENT_TYPES = %w[ + image/png + image/jpeg + image/gif + ].freeze + + delegate :blob, to: :value + + delegate :content_type, :byte_size, to: :blob + + def perform + return unless value.attached? + + unless content_type.in? CONTENT_TYPES + error :image_format, content_type: content_type + end + + error :image_size unless byte_size <= MAX_SIZE + end + end +end diff --git a/config/application.rb b/config/application.rb index 81e1e06..d73ce2a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -41,6 +41,11 @@ module Partynest # Fully qualified domain name. config.site_domain = 'libertarian-party.com' + # Custom directories with classes and modules you want to be autoloadable. + config.autoload_paths += [ + config.root.join('app', 'validators'), + ] + # Email which all mail is set from. config.noreply_email_address = "no-reply@#{config.site_domain}" config.noreply_email_contact = diff --git a/config/locales/activerecord/en.yml b/config/locales/activerecord/en.yml index a6e0052..7f8e787 100644 --- a/config/locales/activerecord/en.yml +++ b/config/locales/activerecord/en.yml @@ -108,9 +108,6 @@ en: unlock_token: Unlock token updated_at: Updated at errors: - models: - account: - attributes: - avatar: - size: 'has too big size' - format: 'has invalid format: %{content_type}' + messages: + image_size: 'has too big size' + image_format: 'has invalid format: %{content_type}' diff --git a/config/locales/activerecord/ru.yml b/config/locales/activerecord/ru.yml index 6df8ee1..d67f1d3 100644 --- a/config/locales/activerecord/ru.yml +++ b/config/locales/activerecord/ru.yml @@ -108,9 +108,6 @@ ru: unlock_token: Токен разблокировки updated_at: Дата обновления errors: - models: - account: - attributes: - avatar: - size: 'имеет слишком большой размер' - format: 'имеет неверный формат: %{content_type}' + messages: + image_size: 'имеет слишком большой размер' + image_format: 'имеет неверный формат: %{content_type}' diff --git a/spec/validators/image_validator_spec.rb b/spec/validators/image_validator_spec.rb new file mode 100644 index 0000000..b0bedca --- /dev/null +++ b/spec/validators/image_validator_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe ImageValidator do + pending "add some examples to (or delete) #{__FILE__}" +end