Skip to content

Commit

Permalink
move avatar logic out of controller to an own PORO: AvatarGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
markets committed Jun 16, 2021
1 parent b8d557a commit 2daded2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 43 deletions.
44 changes: 4 additions & 40 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,12 @@ def update
end

def update_avatar
avatar = params[:avatar]
errors = validate_avatar(avatar)
operation = AvatarGenerator.new(current_user, params)

if errors.blank?
current_user.avatar.purge if current_user.avatar.attached?
crop_image_and_save(current_user, avatar)
if operation.errors.empty?
operation.call
else
flash[:error] = errors.join("<br>")
flash[:error] = operation.errors.join("<br>")
end

redirect_to current_user
Expand Down Expand Up @@ -130,38 +128,4 @@ def redirect_to_after_create
name: @user.username)
end
end

def crop_image_and_save(user, avatar)
orig_width = params[:original_width].to_i
width = params[:height_width].to_i
left = params[:width_offset].to_i
top = params[:height_offset].to_i

image_processed = ImageProcessing::MiniMagick.
source(avatar.tempfile).
resize_to_fit(orig_width, nil).
crop("#{width}x#{width}+#{left}+#{top}!").
convert("png").
call

user.avatar.attach(
io: image_processed,
filename: user.username,
content_type: avatar.content_type
)
end

def validate_avatar(file)
errors = []

if User::AVATAR_CONTENT_TYPES.exclude?(file.content_type)
errors << t("users.show.invalid_format")
end

if file.size.to_f > User::AVATAR_MAX_SIZE.megabytes
errors << t("users.avatar.max_size_warning", size: User::AVATAR_MAX_SIZE)
end

errors
end
end
2 changes: 0 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ class User < ApplicationRecord
:timeoutable
]

AVATAR_MAX_SIZE = 5
AVATAR_CONTENT_TYPES = %w[image/jpeg image/pjpeg image/png image/x-png]
GENDERS = %w(
female
male
Expand Down
51 changes: 51 additions & 0 deletions app/services/avatar_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
class AvatarGenerator
MAX_SIZE = 5
CONTENT_TYPES = %w[image/jpeg image/pjpeg image/png image/x-png]

attr_accessor :errors

def initialize(user, params)
@user = user
@params = params
@avatar = params[:avatar]
@errors = []

validate_avatar
end

def call
@user.avatar.purge if @user.avatar.attached?

@user.avatar.attach(
io: process_image,
filename: @user.username,
content_type: @avatar.content_type
)
end

private

def process_image
orig_width = @params[:original_width].to_i
width = @params[:height_width].to_i
left = @params[:width_offset].to_i
top = @params[:height_offset].to_i

ImageProcessing::MiniMagick.
source(@avatar.tempfile).
resize_to_fit(orig_width, nil).
crop("#{width}x#{width}+#{left}+#{top}!").
convert("png").
call
end

def validate_avatar
if CONTENT_TYPES.exclude?(@avatar.content_type)
@errors << I18n.t("users.show.invalid_format")
end

if @avatar.size.to_f > MAX_SIZE.megabytes
@errors << I18n.t("users.avatar.max_size_warning", size: MAX_SIZE)
end
end
end
2 changes: 1 addition & 1 deletion spec/controllers/users_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@
end

it "don't change the photo attached if the file size it too big" do
allow_any_instance_of(ActionDispatch::Http::UploadedFile).to receive(:size) { User::AVATAR_MAX_SIZE.megabytes + 1.megabyte }
allow_any_instance_of(ActionDispatch::Http::UploadedFile).to receive(:size) { AvatarGenerator::MAX_SIZE.megabytes + 1.megabyte }

put :update_avatar, params: { avatar: uploaded_file }

Expand Down

0 comments on commit 2daded2

Please sign in to comment.