Cropping Images using jCrop jQuery plugin in Rails

Cài đặt gem carierwave

Thêm gem rmagick và carierwave vào Gemfile.

gem 'rmagick'
gem 'carrierwave'

Trên Mac, bạn có thể cài đặt imagemagick sữ dụng brew

brew install imagemagick

Tạo ra một uploader tên là Avatar

rails generate uploader Avatar

Khởi tạo một model User có 2 trường là name và avatar

rails g model user name avatar.

Thiết lập carrirwave uploader trong model User

class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader
end

Tạo ra một controller user

rails g controller users

Chạy migration

rails db:migrate

Định nghĩa resource trong routes.rb

Rails.application.routes.draw do
  resources :users
  root to: 'users#index'
end

Thêm đoạn code sau vào file uploaders/avatar_uploader.rb

include CarrierWave::RMagick

version :thumb do
  resize_to_fill(100, 100)
end

Xử lý crop image

Trong file uploaders/avatar_uploader.rb, thêm large version của hình ảnh và phương thức crop.

version :large do
  resize_to_limit(600, 600)
end

def crop
  if model.crop_x.present?
    resize_to_limit(600, 600)
    manipulate! do |img|
      x = model.crop_x.to_i
      y = model.crop_y.to_i
      w = model.crop_w.to_i
      h = model.crop_h.to_i
      img.crop!(x, y, w, h)
    end
  end
end

Thay đổi action update và create trong users controller để xữ lý chức năng crop.

def update
  @user = User.find(params[:id])
  if @user.update_attributes(allowed_params)
    if params[:user][:avatar].present?
      render :crop
    else
      redirect_to @user, notice: "Successfully updated user."
    end
  else
    render :new
  end
end

def create
  @user = User.new(allowed_params)
  if @user.save
    if params[:user][:avatar].present?
      render :crop
    else
      redirect_to @user, notice: "Successfully created user."
    end
  else
    render :new
  end
end

Thêm file crop.html.erb vào thư mục app/views/users.

<h1>Crop Avatar</h1>
<%= image_tag @user.avatar_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:100px; height:100px; overflow:hidden">
  <%= image_tag @user.avatar.url(:large), :id => "preview" %>
</div>
<%= form_for @user do |f| %>
  <% %w[x y w h].each do |attribute| %>
    <%= f.hidden_field "crop_#{attribute}" %>
  <% end %>
  <div class="actions">
    <%= f.submit "Crop" %>
  </div>
<% end %>

Thêm đoạn code sau vào model User:

  attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
  after_update :crop_avatar

  def crop_avatar
    avatar.recreate_versions! if crop_x.present?
  end

Download jcrop jquery plugin từ jcrop website. Copy file jquery.Jcrop.css vào thưc mục vendor/assets/stylesheets và file jquery.Jcrop.js vào thư mục vendor/assets/javascripts. Trong file application.js, thêm:

//= require jquery.Jcrop

Trong file application.css, thêm:

*= require jquery.Jcrop

File users.coffee:

jQuery ->
 new AvatarCropper()

class AvatarCropper
 constructor: ->
   $('#cropbox').Jcrop
     aspectRatio: 1
     setSelect: [0, 0, 600, 600]
     onSelect: @update
     onChange: @update

 update: (coords) =>
   $('#user_crop_x').val(coords.x)
   $('#user_crop_y').val(coords.y)
   $('#user_crop_w').val(coords.w)
   $('#user_crop_h').val(coords.h)
   @updatePreview(coords)

 updatePreview: (coords) =>
   $('#preview').css
       width: Math.round(100/coords.w * $('#cropbox').width()) + 'px'
       height: Math.round(100/coords.h * $('#cropbox').height()) + 'px'
       marginLeft: '-' + Math.round(100/coords.w * coords.x) + 'px'
       marginTop: '-' + Math.round(100/coords.h * coords.y) + 'px'

Nó sẽ làm việc ngay bây giờ. Tuy nhiên, bức ảnh sẽ vẫn hiển thị những phần chưa được cắt. Để fix nó, thêm process :crop vào version :thumb trong avatar_uploader.rb

version :thumb do
 process :crop
 resize_to_fill(100, 100)
end

Tham khảo

https://rubyplus.com/articles/3951-Cropping-Images-using-jCrop-jQuery-plugin-in-Rails-5