ruby-on-rails - Rails 5.2 ActiveStorage 上传图片及用户如何裁剪图片

标签 ruby-on-rails rails-activestorage

我曾经使用carrierwaveJcrop 上传和裁剪用户图片,效果很好。用户可以自由裁剪然后上传图片。但现在我想将上传方式从carrierwave更改为ActiveStorage。这时候我也想自由裁剪图片。那我怎么能改变我的代码呢?非常感谢!!

我的gems部分:

gem 'rails', '~> 5.2'
gem 'mini_magick'

# gem 'carrierwave', '~> 1.2', '>= 1.2.2'**(No use in ActiveStorage)**

我的部分用户 models :

# user.rb

has_one_attached :picture
has_one_attached :avatar

attr_accessor :remember_token, :activation_token, :crop_x, :crop_y, :crop_w, :crop_h

after_update :crop_picture

def crop_picture
    picture.recreate_versions! if crop_x.present?
end
# mount_uploader :picture, PictureUploader**(No use in ActiveStorage)**
  # mount_uploader :avatar, PictureUploader**(No use in ActiveStorage)**

我的 user_controllers 的一部分:

 def new
    @user = User.new
  end

 def create
    @user = User.new(user_params) 
    if @user.save
      log_in @user
      flash[:success] = "Almost success"
      redirect_to confirmation_path(@user.name)
    else
      flash.now[:danger] = 'Failure'
      render :new
    end
  end

def update
    @user = User.friendly.find(params[:id])
    if @user.update_attributes(user_params)
      if params[:user][:picture].present?
        render :crop
      else
        redirect_to @user
        flash[:success] = "Update success"
      end
    else
      flash[:warning] = "Update failue"
      render :edit
    end
  end

private

  def user_params
    params.require(:user).permit(... :avatar, :picture)
  end

我的crop.html.erb:

<div class="container">
  <div class="col-md-12 pbt20 bgCo">
    <div class="col-md-8">
      <h4 class="pageItemTitle mbt20">Crop Picture</h4>
      <%#= image_tag @user.picture.url(:large), :id => "user_preview" %>
      <%= image_tag(@user.picture.variant(combine_options: { gravity: 'Center', crop: '600x800+0+0' }),width: 600,id: "cropImage")  %>
    </div>
    <div class="col-md-4">
      <h4 class="pageItemTitle mbt20">Crop Preview</h4>
      <div style="width:160px; height:160px; overflow:hidden; border-radius: 50%;">
        <%= image_tag @user.picture, :id => "user_preview" %>
      </div>
      <div class="crop-footer pull-right mbt20 pbt20">
        <%= form_for @user do |f| %>
          <% %w[x y w h].each do |attribute| %>
            <%= f.hidden_field "crop_#{attribute}" %>
          <% end %>
          <%= link_to "Close", @user,  class: "btn btn-default mr10" %>
          <%= f.submit "Crop", class: "btn btn-primary" %>
        <% end %>
      </div>
    </div>

  </div>
</div>

我的crop.js.coffee:

jQuery ->
  new PictureCropper()

class PictureCropper
  constructor: ->
    $('#cropImage').Jcrop
      aspectRatio: 1
      setSelect: [0, 0, 400, 400]
      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) =>
    $('#user_preview').css
      width: Math.round(160/coords.w * $('#cropImage').width()) + 'px'
      height: Math.round(160/coords.h * $('#cropImage').height()) + 'px'
      marginLeft: '-' + Math.round(160/coords.w * coords.x) + 'px'
      marginTop: '-' + Math.round(160/coords.h * coords.y) + 'px'

我的picture.uploader:(在ActiveStorage中没有用)

class PictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  storage :file

  def store_dir
    "uploaders/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :large do
    process :crop
    resize_to_limit(600, nil)
  end

  def crop
    if model.crop_x.present?
      resize_to_limit(600, nil)
      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([[w, h].join('x'),[x, y].join('+')].join('+'))
      end
    end
  end

  def extension_white_list
    %w(jpg jpeg gif png)
  end

  def filename
    s = "#{model.id}"
    t = s.to_i * 365
    t.to_s + ".jpg" if original_filename
  end

end

如果我把上传方式从carrierwave改成ActiveStorage,此时我也想自由裁剪图片给用户。那我怎么能改变我的代码呢?非常感谢!!

最佳答案

我将裁剪坐标存储为 PostgreSQL 中名为 crop_settingsjson 字段。

下面是生成缩略图变体和裁剪图像变体的工作代码。

#Event.rb

class Event < ApplicationRecord
  attr_accessor :crop_x, :crop_y, :crop_w, :crop_h

  has_one_attached :cover_image
  before_save :check_cropping 

  def check_cropping
    self.crop_settings = {x: crop_x, y: crop_y, w: crop_w, h: crop_h} if cropping?
  end 

  def cropping?
    !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank?
  end

  def cropped_image
    if cover_image.attached?
      if crop_settings.is_a? Hash
        dimensions = "#{crop_settings['w']}x#{crop_settings['h']}"
        coord = "#{crop_settings['x']}+#{crop_settings['y']}"
        cover_image.variant(
          crop: "#{dimensions}+#{coord}"
        ).processed
      else
        cover_image
      end
    end
  end

  def thumbnail(size = '100x100')
    if cover_image.attached?
      if crop_settings.is_a? Hash
        dimensions = "#{crop_settings['w']}x#{crop_settings['h']}"
        coord = "#{crop_settings['x']}+#{crop_settings['y']}"
        cover_image.variant(
        crop: "#{dimensions}+#{coord}",
        resize: size
        ).processed
      else
        cover_image.variant(resize: size).processed
      end
    end
  end
end

views/events/show.html.erb

...
<div>
  Original Image:
  <%= image_tag(@event.cover_image) if @event.cover_image.attached? %>
</div>
<div>
  Cropped Image:
  <%= image_tag(@event.cropped_image) if @event.cropped_image %>
</div>
<div>
  Thumbnail:
  <%= image_tag(@event.thumbnail) if @event.thumbnail %>
</div>
 ...

enter image description here

如果以前创建并存储了变体,那么将使用它而不是重新创建。

enter image description here

关于ruby-on-rails - Rails 5.2 ActiveStorage 上传图片及用户如何裁剪图片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51723108/

相关文章:

ruby-on-rails - 使用 Ruby on Rails 发送邮件的最简单方法

ruby-on-rails - 用于 Rails 应用程序的 R 统计包 Gem

ruby-on-rails - 在 Active Record 查询中包含 Active Storage 附件

ruby-on-rails - 如何向 ActiveStorage 添加自定义服务

ruby-on-rails - 是否应该将 Active Storage 二进制变体文件推送到版本控制?

ruby-on-rails - 如何重写find_by方法然后调用activerecord中的原始方法

mysql - Heroku 的 Rails 数据库特定查询

jquery - Ajax beforeSend 在 Rails 上只能运行一次

ruby-on-rails - 获取磁盘上 ActiveStorage 文件的路径

ruby-on-rails - Rails 主动存储 : Get relative disk service path for attachment