Question

My uploader is working well apart from one small thing. The setting of default images. I'm using carrierwave for users to upload profile images of themselves:

user model

class User < ActiveRecord::Base     
    has_one :avatar, class_name: 'Image', foreign_key: :user_id

    before_create :create_fallback_image

    def create_fallback_image
        self.create_avatar
    end
end

image model

class Image < ActiveRecord::Base

    mount_uploader :file_name, AvatarUploader, auto_validate: false

    belongs_to :user
end

avatar uploader

class AvatarUploader < BaseUploader

  include CarrierWave::RMagick

  storage :file

  process resize_to_fit: [75, 75]
  process convert: 'gif'

  def default_url
   'foobar'
  end

  def filename
      random_string + '.gif'
    end
  end

  def random_string
    @random_string ||= User.random_string
  end
end

When a user signs up without uploading an optional profile image, they are assigned an association to their profile image, but instead of the default_url working, they get a random string from the filename method.

I thought I could get around it like this:

user model

class User < ActiveRecord::Base     
    has_one :avatar, class_name: 'Image', foreign_key: :user_id

    before_create :create_fallback_image

    def create_fallback_image
            # look here:

        self.create_avatar.create_fallback
    end
end

image model

class Image < ActiveRecord::Base

    mount_uploader :file_name, AvatarUploader, auto_validate: false

    belongs_to :user

    def create_fallback
       self.update_attributes(file_name: 'my_fallback.jpg')
    end
end

and while it nearly, nearly works, when I update the attributes of the file_name column, the uploader kicks in and my_fallback.jpg is overridden by a random string from my random_string method!

Was it helpful?

Solution

Carrierwave has a built-in fallback mechanism for default image

Update your default_url method in AvatarUploader as below:

  def default_url
    ActionController::Base.helpers.asset_path("fallback/" + [version_name, "my_fallback.jpg"].compact.join('_'))
  end

where change fallback/ to your desired folder path. This way, when an avatar is not uploaded for a particular user then my_fallback.jpg would be used as fallback image.

Refer to section Providing a default URL in Carrierwave Documentation.

when I update the attributes of the file_name column, the uploader kicks in and my_fallback.jpg is overridden by a random string from my random_string method!

This happens because you have overridden filename method in AvatarUploader which gets called every time an image is uploaded. If you notice, its calling random_string method in it. Hence, you get a random string as your filename.

UPDATE

As per the chat session with OP, if an avatar is not uploaded for a user then a default image should be shown. I suggested the following helper :

module ApplicationHelper
  def display_avatar(user)  
    unless user.avatar.nil? 
      image_tag(user.avatar.file_name) 
    else
      image_tag("/path/to/fallback.jpg")
     end    
  end
  ## ...
end

Use this helper method in views to display avatar image appropriately.

OTHER TIPS

Also, you can do it within model:

class User < ApplicationRecord
  has_one :avatar, class_name: 'User::Avatar', as: :parent, dependent: :destroy
  accepts_nested_attributes_for :avatar, allow_destroy: true #, ...

  def avatar
    super || build_avatar
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top