Starting a new Rails 4 : VI. Attachments with Carrierwave and Jasny rails 4, carrierwave, minimagick, bootstrap 3, fileupload

Roadmap

I want to manage attachments : for starting, some avatar for users, and some files linked to projects in future.

First install ImageMagick : it need for all the mini magick stuff (as usual, in /c/dev for me).

Carrierwave start with avatar for user

After installed carrierwave in gemfile (with mini_magick gem too for image processing), starting with :

rails g uploader avatar

witch create app/uploaders/avatar.rb with some change :

    include CarrierWave::MiniMagick
    def default_url
      asset_path [version_name, "default_user_avatar_huge.png"].compact.join('_'))
    end
    version :small do
      process :resize_to_fill => [32, 32]
    end
    def extension_white_list
      %w(jpg jpeg gif png)
    end
    

Where default_user_avatar_huge.png is a fallback avatar image in assets/images. (with a small version 32x32 named small_default_user_avatar_huge.png)

ActiveRecord integration

First add an avatar string column to the user model, and migrate.

rake g migration AddAvatarToUsers avatar:string

And ajust the models/user.rb :

mount_uploader :avatar, AvatarUploader

Validations on the model

For the file size, check out the solution https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Validate-attachment-file-size and apply it in our model user :

    require 'file_size_validator' 

    class User < ActiveRecord::Base
      authenticates_with_sorcery!
      ...

      validates :avatar, 
        :file_size => { :maximum => 5.megabytes.to_i} 
    end 
    

Also we validate the processing and the file type (see https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Validate-uploads-with-Active-Record) in models/user.rb :

validates_integrity_of :avatar
validates_processing_of :avatar

And this is the full config/locales/en.yml :

    en:
      errors:
        messages:
          wrong_size: "is the wrong size (should be %{file_size})"
          size_too_small: "is too small (should be at least %{file_size})"
          size_too_big: "is too big (should be at most %{file_size})"
          carrierwave_processing_error: "failed to be processed"
          carrierwave_integrity_error: "is not an allowed file type"    
          carrierwave_download_error: "Couldn't download image."
    

and the models/user.rb :

    class User < ActiveRecord::Base
      ...
      mont_uploader :avatar, AvatarUploader
      validates :avatar, 
        :presence => true , 
        :file_size => { :maximum => 5.megabytes.to_i} 
      validates_integrity_of :avatar
      validates_processing_of :avatar   
    end 
    

User Views

In the index view :

    %td= image_tag user.avatar.small.url
    

In the form view : (the remove_avatarand avatar_cache are specials fields build by carrierwave for removing the avatar and keep a cache of uploaded image when the form is reloaded if some validation has failed).

    = f.input :avatar, :as => :file
    = f.input :remove_avatar, :as => :boolean
    = f.input :avatar_cache, :as => :hidden
    

Add also those fields to the method user_params in the controllers/users_controller.rb

In the show view :

    = link_to image_tag(@user.avatar.small.url), '#modal_avatar', :role => 'button', 'data-toggle'=>'modal'
    ...
    #modal_avatar.modal.fade
      .modal-dialog
        .modal-content
          .modal-header
            = button_close_modal
            %h4 Image
          .modal-body
            = image_tag @user.avatar.url, :style => 'max-height: 400px;max-width: 400px;margin: 0 auto;display:block;', :class => 'img-thumbnail'
          .modal-footer
    

The modal dialog show the image in full size (CSS have to move…).

Bootstrap 3 and Jasny FileUpload

I use a part of Jasny Bootstrap enhancement : go to http://jasny.github.io/bootstrap/javascript.html#fileupload, click on the button ‘download’ and copy the .css and the .js files you just just get in the correspondent /assets/ folder.

Now in the \form.html.haml replace the

    = f.input :avatar, :as => :file
    

with

    = render partial: 'file_upload', :locals => {f: f}
    

and create the partial app/views/users/_file_upload.html.haml :

    .control-group.file.optional.user_avatar
      %label.file.optional.control-label{for: "user_avatar"} Avatar
      .controls
        .fileupload.fileupload-new{"data-provides" => "fileupload"}
          .fileupload-new.thumbnail{style: "width: 50px; height: 50px;"}= image_tag @user.avatar.small.url
          .fileupload-preview.fileupload-exists.thumbnail{style: "width: 50px; height: 50px;"}
          %span.btn.btn-file.btn-primary
            %span.fileupload-new Select image
            %span.fileupload-exists Change
            = f.input_field :avatar, :as => :file
          = link_to "Remove", "#", class: "btn fileupload-exists", "data-dismiss" => "fileupload"
    

comments powered by Disqus