12/08/2018, 17:59

CẮT ẢNH VỚI CARRIER WAVE TRONG RAILS (CROPPING IMAGES)

Chúng ta thương thấy khi upload một ảnh (thường là avatar có kích thước quá lớn) các trang web thường cung cấp tùy chỉnh ảnh hay còn gọi là copping. Kỹ thuật cropping được áp dụng rất nhiều trong thực tế, vậy trong rails chúng ta làm thế nào? Sau đây là bài hướng dẫn cropping images trong rails ...

Chúng ta thương thấy khi upload một ảnh (thường là avatar có kích thước quá lớn) các trang web thường cung cấp tùy chỉnh ảnh hay còn gọi là copping. Kỹ thuật cropping được áp dụng rất nhiều trong thực tế, vậy trong rails chúng ta làm thế nào? Sau đây là bài hướng dẫn cropping images trong rails thông qua thư viện Jcrop. Trước tiên chúng ta phải thêm gem rmagick và carrierwave vào trong gem file:

gem 'rmagick'
gem 'carrierwave'

Tạo model User với hai trường name và avatar đều để dạng string:

rails g model user name:string avatar:string
rails db:migrate

Tạo file uploader của gem carrierwave bằng câu lệnh sau:

rails generate uploader Avatar

Cài đặt carrierwave uploader cho trường avatar trong User model:

class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader
end

Tạo users_controller:

rails g controller users

Định nghĩa các action trong routes:

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

Tại file uploaders/avatar_uploader.rb thêm các phiên bản kích cỡ của ảnh mà bạn muốn tùy chỉnh:

class AvatarUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  storage :file

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :large do
    resize_to_limit(600, 600)
  end

  version :thumb do
    process :crop
    resize_to_fill(100, 100)
  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
end

Thêm file crop.html.erb vào trong thư mục app/views/users nhằm mục đích tùy chỉnh images sau khi user tạo avatar:

<h1>Crop Avatar</h1>
<%= image_tag @user.avatar_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="awidth: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 action: create, update trong users_controller nhằm mục đích xử lý việc cắt ảnh:

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

Để cắt ảnh chúng ta sẽ sử dụng một thư viện của js có tên là Jcop, bạn có thể download jcop tại đây. Copy jquery.Jcrop.css vào thư mục vendor/assets/stylesheets và jquery.Jcrop.js vào thư mục vendor/assets/javascripts. Tại application.js, thêm dòng:

//= require jquery.Jcrop

Tại application.css, thêm dòng:

*= require jquery.Jcrop

Tại file crop.js nhằm tùy chỉnh lại giao diện cắt ảnh:

var AvatarCropper,
  bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
jQuery(function() {
  return new AvatarCropper();
});
AvatarCropper = (function() {
  function AvatarCropper() {
    this.updatePreview = bind(this.updatePreview, this);
    this.update = bind(this.update, this);
    $('#cropbox').Jcrop({
      aspectRatio: 1,
      setSelect: [0, 0, 600, 600],
      onSelect: this.update,
      onChange: this.update
    });
  }
  AvatarCropper.prototype.update = function(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);
    return this.updatePreview(coords);
  };
  AvatarCropper.prototype.updatePreview = function(coords) {
    return $('#preview').css({
      awidth: Math.round(100 / coords.w * $('#cropbox').awidth()) + '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'
    });
  };
  return AvatarCropper;
})();

Và đây là thành quả của chúng ta:

Link tham khảo:

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

0