【问题标题】:carrierwave doesn't save file neither update modelcarrierwave 不保存文件也不更新模型
【发布时间】:2017-12-04 19:49:07
【问题描述】:

您好,我在我的 rails api 中使用carrierwave 来上传用户头像...在我的控制器中,我有一个方法 update_avatar 可以使用给定文件更新 user.avatar_uri。

我查看了carrierwave 的文档并遵循了每一步,但它不起作用。它既不保存文件也不保存模型本身..

这是控制器 users_controller.rb

    def update_avatar
    parameters = Hash.new
    user = User.find_by(id: params[:user_id])
    if user
      #p("----user.avatar_uri.url before user.avatar_uri = params[:avatar] : "+user.avatar_uri.url)

      user.is_used_fb_avatar=false
      p("----user.avatar_uri.url before update: "+ user.avatar_uri.url)
      User.update(params[:user_id], :avatar_uri => params[:avatar])
      p("----user.avatar_uri.url after update: "+user.avatar_uri.url)


      if  user.avatar_uri

        parameters["success"]=true
        parameters["avatar_uri"]=user.avatar_uri.url
      else
        parameters["success"]=false
        parameters["error"]="Couldn't update user check the file used"
      end
    else
      parameters["success"]=false
      parameters["error"]="Couldn't find user"
    end
    render :json => parameters.to_json
  end

这是模型 user.rb

     class User < ApplicationRecord
      # Include default devise modules. Others available are:
      # :confirmable, :lockable, :timeoutable and :omniauthable
      mount_uploader :avatar_uri, AvatarUploader
      attr_accessor :login
      has_one :role, dependent: :destroy
      has_many :posts, dependent: :destroy
      has_many :likes, dependent: :destroy
      has_many :shares, dependent: :destroy
      has_many :comments, dependent: :destroy
      has_many :messages
      has_many :notifications, dependent: :destroy
      has_many :follows, class_name: "Follow", foreign_key: "follower_id", dependent: :destroy
      has_many :tokens
      has_and_belongs_to_many :conversations
    ...
end

这是上传者 avatar_uploader.rb

class AvatarUploader < CarrierWave::Uploader::Base

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog
  def store_dir
    "#{model.class.to_s.underscore}/image"
  end

  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  def cache_dir
    "tmp/"
  end

  def filename
    if model.is_used_fb_avatar
      original_filename
      #puts ("--------- is_used_fb_avatar is called ----")
    else
      SecureRandom.urlsafe_base64(16).to_s+ File.extname(original_filename).to_s if original_filename
      puts ("--------- is_used_fb_avatar is not called ----")
      puts ("filename => "+ SecureRandom.urlsafe_base64(16).to_s+File.extname(original_filename).to_s)
    end
  end


end

这是我从服务器获取的控制台日志:

Started PUT "/api/update-user-avatar.json" for 127.0.0.1 at 2017-06-30 21:10:43 +0200
Processing by Api::UsersController#update_avatar as JSON
  Parameters: {"user_id"=>"47", "avatar"=>#<ActionDispatch::Http::UploadedFile:0x007f852d2c54e8 @tempfile=#<Tempfile:/var/folders/k7/2bnc1fxs1r164gf831dn5l140000gn/T/RackMultipart20170630-1261-1viplk8.jpg>, @original_filename="batman.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"avatar\"; filename=\"batman.jpg\"\r\nContent-Type: image/jpeg\r\n">}
  User Load (0.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 47], ["LIMIT", 1]]
"----user.avatar_uri.url before update: /user/image/wlOHg5N0K5aq5hJGFlM6XA.png"
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 47], ["LIMIT", 1]]
   (0.3ms)  BEGIN
  User Exists (0.5ms)  SELECT  1 AS one FROM "users" WHERE "users"."username" = $1 AND ("users"."id" != $2) LIMIT $3  [["username", "John"], ["id", 47], ["LIMIT", 1]]
--------- is_used_fb_avatar is not called ----
filename => jDZ48CtHI5a9L0qGcKdEWQ.jpg
  SQL (37.7ms)  UPDATE "users" SET "updated_at" = $1, "avatar_uri" = $2 WHERE "users"."id" = $3  [["updated_at", 2017-06-30 19:10:45 UTC], ["avatar_uri", "wlOHg5N0K5aq5hJGFlM6XA.png"], ["id", 47]]
--------- is_used_fb_avatar is not called ----
filename => njeFYobP6erVu9uYunmFhw.jpg
   (134.3ms)  COMMIT
"----user.avatar_uri.url after update: /user/image/wlOHg5N0K5aq5hJGFlM6XA.png"
Completed 200 OK in 683ms (Views: 136.7ms | ActiveRecord: 222.4ms)

可以看到上传器中的 def 文件名被调用了两次,没有保存模型,也没有保存文件...

“wlOHg5N0K5aq5hJGFlM6XA.png”是 avatar_uri 列的旧值,它不会被新的“njeFYobP6erVu9uYunmFhw.jpg”替换..

==>[回答]: 感谢@Micael Nussbaumer 解决了它......问题是直接在我的上传器中使用 SecureRandom 所以我将其更改为:

def filename
    if model.is_used_fb_avatar
      original_filename
      #puts ("--------- is_used_fb_avatar is called ----")
    else
      "avatar-#{secure_token}.jpg" if original_filename.present?
    end
  end

  protected

  def secure_token
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
  end

【问题讨论】:

  • 我总是初始化字段,所以不确定这可能是问题所在,尝试像这样user.avatar_uri = AvatarUploader.new user.avatar_uri = params[:avatar] user.save! 这样做,然后在上传器上,def 文件名,在打印语句之后放置SecureRandom.urlsafe_base64(16).to_s+ File.extname(original_filename).to_s if original_filename?跨度>
  • 嗯,它实际上正在工作,但没有按预期工作:它保存文件但用另一个名称更新 user.avatar_uri ...这是日志中的几行:SQL (84.0ms) UPDATE "users" SET "avatar_uri" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["avatar_uri", "NghyuZZ6vvdtiWFQrO6m4w.jpg"], ["updated_at", 2017-06-30 20:22:22 UTC], ["id", 47]]--------- is_used_fb_avatar is not called ----filename =&gt; mcXKz1hV6vfkMid23l4ixw.jpg (21.7ms) COMMIT "----user.avatar_uri.url after update: /user/image/8TMtcBHpibaFELwIITo07Q.jpg"
  • SecureRandom.urlsafe_base64(16).to_s+ File.extname(original_filename).to_s if original_filename puts ("--------- is_used_fb_avatar is not called ----") puts ("filename =&gt; "+ SecureRandom.urlsafe_base64(16).to_s+File.extname(original_filename).to_s)这里基本上 def 文件名会返回这个 ->>>> puts ("filename => "+ SecureRandom.urlsafe_base64(16).to_s+File. extname(original_filename).to_s),它应该返回名称而不是 puts 语句?因此,也许如果您将第一个securerandom...分配给一个var,然后放入该var,最后返回该var ->> if original_filename

标签: ruby-on-rails file controller carrierwave uploader


【解决方案1】:

试试这个:

def filename
  "avatar-#{secure_token}.jpg" if original_filename.present?
end

protected

def secure_token
  var = :"@#{mounted_as}_secure_token"
  model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end

Source for filenaming in carrierwave uploader

【讨论】:

  • 试过了......还是一样......我什至尝试完全删除puts:def filename if model.is_used_fb_avatar original_filename #puts ("--------- is_used_fb_avatar is called ----") else new_file_name = SecureRandom.urlsafe_base64(16).to_s+ File.extname(original_filename).to_s new_file_name if original_filename end end
  • 问题是由于某种原因它在更新后再次被调用:SQL (0.8ms) UPDATE "users" SET "avatar_uri" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["avatar_uri", "_7AD618In4cyI-IBTtznbg.jpg"], ["updated_at", 2017-06-30 21:04:57 UTC], ["id", 47]] --------- is_used_fb_avatar is not called ---- filename =&gt; twmSWb8NaMLymWfDWzhqdw.jpg (37.5ms) COMMIT "----user.avatar_uri.url after update: /user/image/twmSWb8NaMLymWfDWzhqdw.jpg" Completed 200 OK in 940ms (Views: 78.7ms | ActiveRecord: 550.1ms) 这就是为什么它与保存的文件名不同
  • @AhmedFnayou 我添加了一个我的工作上传者的样本,你能试试吗?也许它只是 original_filename.present?那个不见了?
  • 是的...您的代码运行良好...终于!我只尝试了 .present?起初但它不起作用..所以我只是添加了您的secure_token方法并像您一样使用它...它起作用了!谢谢楼主:)
猜你喜欢
  • 1970-01-01
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 2017-04-25
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
相关资源
最近更新 更多