Rails在从params分配虚拟属性之前运行ImageUploader

时间:2014-11-06 04:56:55

标签: ruby-on-rails ruby image-processing ruby-on-rails-4

我试图在我的Rails应用程序中应用Jcrop,前端部分工作正常,无需在此处发布代码。问题是当我尝试创建时。 Rails由于某种原因在分配我创建的虚拟属性之前运行ThumbnailUploader中的代码。

根据我检查的内容,此行执行ThumbnailUploader代码:

@thumbnail = Thumbnail.new(thumbnail_params)

thumbnail_params 所有坐标都没问题,我查了一下,但是由于某些我不知道的原因,它没有在ThumbnailUploader中设置要裁剪的变量。

当我更新时,它按预期工作100%。我要粘贴我的 ThumbnailController ,我的缩略图模型和我的 ThumbnailUploader ,这样你们就可以检查一下:

  • Rails -v:4.1.6

  • Ruby -v:2.1.3

宝石

  • gem' rmagick',:require => ' RMagick'
  • gem' carrierwave'
  • gem' fog'
  • gem' carrierwave_direct'

ThumbnailController

class ThumbnailsController < ApplicationController
  before_action :set_thumbnail, only: [:show, :edit, :update, :destroy]

  # GET /thumbnails
  # GET /thumbnails.json
  def index
    @thumbnails = Thumbnail.all
  end

  # GET /thumbnails/1
  # GET /thumbnails/1.json
  def show
  end

  # GET /thumbnails/new
  def new
    @thumbnail = Thumbnail.new           
  end  

  # POST /thumbnails
  # POST /thumbnails.json
  def create    
    @thumbnail = Thumbnail.new(thumbnail_params)

    respond_to do |format|
      if @thumbnail.save
        format.html { redirect_to root_url }
        format.json { render :show, status: :created, location: @thumbnail }        
      else
        format.html { render :new }
        format.json { render json: @thumbnail.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /thumbnails/1
  # PATCH/PUT /thumbnails/1.json
  def update    
    @thumbnail.crop_x = thumbnail_params[:crop_x]
    @thumbnail.crop_y = thumbnail_params[:crop_y]
    @thumbnail.crop_w = thumbnail_params[:crop_w]
    @thumbnail.crop_h = thumbnail_params[:crop_h]

    respond_to do |format|
      if @thumbnail.update(thumbnail_params)
        Post.cached_find(@thumbnail.post.id).thumbnail.touch
        format.html { redirect_to root_url, notice: 'Thumbnail was successfully updated.' }
        format.json { render :show, status: :ok, location: @thumbnail }
      else
        format.html { render :edit }
        format.json { render json: @thumbnail.errors, status: :unprocessable_entity }
      end
    end
  end
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_thumbnail
      @thumbnail = Thumbnail.find(params[:id])          
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def thumbnail_params
      params.require(:thumbnail).permit(:image, :crop_x, :crop_y, :crop_w, :crop_h)
    end
  end

Thumbnail.rb:

class Thumbnail < ActiveRecord::Base  
  attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
  belongs_to :post
  mount_uploader :image, ThumbnailUploader
end

ThumbnailUploader:

# encoding: utf-8

class ThumbnailUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :fog

  # 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

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process :resize_to_fit => [50, 50]
  # end
  # 
  # Process files as they are uploaded:
  process :crop

  def crop
    if model.crop_x.nil?  
      ###   WHERE MY PROBLEM LIVES ####
      #### !!!!! model.crop_x IS ALWAYS NIL WHEN TRYING TO CREATE !!!! #####       
      resize_to_fill(256, 256)    
      convert('jpg')
      manipulate! do |img|
        img.crop!(0, 10, 256, 238)
      end
    else
      #### THIS IS WHERE I WANT TO GET, I GET HERE WHEN UPDATE ####
      resize_to_fill(800, 440)
      convert('jpg')
      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
      resize_to_fill(256, 238)
    end
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  # def extension_white_list
    # %w(jpg jpeg gif png)
  # end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  def filename
    super.chomp(File.extname(super)) + '.jpg' if original_filename
  end

end

这是我的表格。 输出标记是用户选择要上传的图像后显示图像的位置,以便他可以选择要裁剪的位置:

  <output id="list"></output>
  <br />
  <br />

  <% %w[x y w h].each do |att| %>
    <%= f.hidden_field "crop_#{att}" %>
  <% end %>

  <p><%= f.file_field :image, required: true, class: 'form-control' %></p>

  <div class="actions">
    <%= f.submit class: 'btn btn-success btn-block disabled', id: 'thumbnail-send' %>
  </div>
<% end %>

我从Ryan Bates RailsCast #182(Revised)

跟踪了这段代码

对不起,如果我错过了什么,这里已经很晚了,我在谷歌上搜索了好几个小时没有结果。希望我在这里有所帮助。

注意: 我已经尝试过做与Update操作相同的事情,它不起作用,因为rails运行:

@thumbnail = Thumbnail.new(thumbnail_params)

之前。并尝试在此行之前添加该代码,它将抛出一个错误,指出crop_x不存在。

1 个答案:

答案 0 :(得分:1)

我找到了解决方案:

def create         
    @thumbnail = Thumbnail.new(      
      crop_x: thumbnail_params[:crop_x],
      crop_y: thumbnail_params[:crop_y],
      crop_w: thumbnail_params[:crop_w],
      crop_h: thumbnail_params[:crop_h],
      image: thumbnail_params[:image]
      )    
...

诀窍。 问题是哈希的顺序。 :image是哈希的第一个元素,因此在设置我创建的attr_accessors之前,Rails会读取并执行它。

所以要小心,Rails在尝试上传之前应首先设置所有内容时会做这个奇怪的事情。