# Bash rails g migration add_avatar_to_users avatar rails g uploader avatar





# Gemfile gem 'mini_magick' gem 'carrierwave' gem 'rails-assets-jcrop', source: 'https://rails-assets.org'





# application.js //= require jcrop





# application.css *= require jcrop





# users_controller.rb def create @user = User.new(user_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 def update @user = User.find(params[:id]) if @user.update_attributes(user_params) if params[:user][:avatar].present? render :crop else redirect_to @user, notice: "Successfully updated user." end else render :new end end ... def user_params params.require(:user).permit(:name, :avatar, :crop_x, :crop_y, :crop_w, :crop_h) end





# user.rb class User < ApplicationRecord mount_uploader :avatar, AvatarUploader 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 end





# uploaders/avatar_uploader.rb class AvatarUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick storage :file version :thumb do process :crop resize_to_fill(100, 100) end version :tiny, from_version: :thumb do process resize_to_fill: [20, 20] end 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 # [[w, h].join('x'),[x, y].join('+')].join('+') => "wxh+x+y" img.crop([[w, h].join('x'),[x, y].join('+')].join('+')) end end end end





# users.coffee $ -> new AvatarCrop() class AvatarCrop constructor: -> width = parseInt($('#cropbox').width()) height = parseInt($('#cropbox').height()) $('#cropbox').Jcrop aspectRatio: 1 setSelect: [0, 0, width, height] 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) => rx = 100 / coords.w ry = 100 / coords.h $('#preview').css width: Math.round(rx * $('#cropbox').width()) + 'px' height: Math.round(ry * $('#cropbox').height()) + 'px' marginLeft: '-' + Math.round(rx * coords.x) + 'px' marginTop: '-' + Math.round(ry * coords.y) + 'px'





# users.js var AvatarCrop, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; $(function() { return new AvatarCrop(); }); AvatarCrop = (function() { function AvatarCrop() { this.updatePreview = bind(this.updatePreview, this); this.update = bind(this.update, this); var height, width; width = parseInt($('#cropbox').width()); height = parseInt($('#cropbox').height()); $('#cropbox').Jcrop({ aspectRatio: 1, setSelect: [0, 0, width, height], onSelect: this.update, onChange: this.update }); } AvatarCrop.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); }; AvatarCrop.prototype.updatePreview = function(coords) { var rx, ry; rx = 100 / coords.w; ry = 100 / coords.h; return $('#preview').css({ width: Math.round(rx * $('#cropbox').width()) + 'px', height: Math.round(ry * $('#cropbox').height()) + 'px', marginLeft: '-' + Math.round(rx * coords.x) + 'px', marginTop: '-' + Math.round(ry * coords.y) + 'px' }); }; return AvatarCrop; })();





# crop.html.erb

<div class='row'> <div class='col-xs-8'> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Crop Avatar</h3> </div> <div class="panel-body"> <%= image_tag @user.avatar_url(:large), id: "cropbox" %> <br> <%= simple_form_for(@user) do |f| %> <% %w[x y w h].each do |attribute| %> <%= f.input "crop_#{attribute}", as: :hidden %> <% end %> <div class="form-actions"> <%= f.button :submit %> </div> <% end %> </div> </div> </div> <div class='col-xs-4'> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">Preview</h3> </div> <div class="panel-body"> <div style="width:100px; height:100px; overflow:hidden"> <%= image_tag @user.avatar.url(:large), id: "preview" %> </div> </div> </div> </div> </div>