File Uploads with Directory in Rails with CarrierWave and Ancestry

Screen Shot 2015-11-22 at 17.59.34

This guide will help you to create structure of directories in your application. In my application is need to create this structure because I had to have files with same name. exp: “all.css, sub/all.css”

I assume that I already know how configure Carrierwave on rails. If not you might have look at this material CarrierWave File Uploads by Ryan Bates

In this tutorial I using this gems:

gem 'carrierwave'
gem 'mini_magick'
gem 'ancestry'

I’m using the inspinia template admin. To more information https://wrapbootstrap.com/theme/inspinia-responsive-admin-theme-WB0R5L90S

Screen Shot 2015-11-22 at 16.22.52.png

models/asset_folder.rb

class AssetFolder < ActiveRecord::Base 
  has_ancestry cache_depth: true 
  validates :name, presence: true  validates :name, format: { with: /\A[a-zA-Z]+\z/ } 
  has_many :assets, :class_name => "Imentore::Asset", :foreign_key => "folder_id
end

models/asset.rb

class Asset < ActiveRecord::Base

belongs_to :folder, :class_name =&gt; Imentore::AssetFolder, :foreign_key =&gt; "folder_id"

attr_accessor :filename
mount_uploader :file, FileUploader

end

app/uploaders/file_uploader.rb

require 'carrierwave/processing/mime_types'

class FileUploader < CarrierWave::Uploader::Base
  include CarrierWave::MimeTypes
  include CarrierWave::MiniMagick
  process :set_content_type
  process :save_content_type_and_size_in_model

  def save_content_type_and_size_in_model
    model.content_type = file.content_type if file.content_type
  end
# Choose what kind of storage to use for this uploader:
storage :file
  def store_dir
    if model.folder.is_root?
      "uploads/#{model.class.to_s.underscore}/#{mounted_as} /#{model.folder.id}/#{model.folder.name.to_underscore}/"
     else
       folders = model.folder.ancestors.map{|x| x.name.downcase}.join('/')
       "uploads/#{model.class.to_s.underscore}/#{mounted_as}    /#{model.folder.id}/#{folders}/#{model.folder.name.to_underscore}"
    end
  end
end

 

Important Thing

I create the initialize below to execute when the new user as created
current_user.folders.create(name: “root”, store: store)

#In my default initialize I created a root directory because this will produce same as this bellow
“uploads/asset/file/1/root”

app/views/asset_folders/index.html.slim

#nestable2.dd
ol.dd-list
- @folders.each do |folder|
li.dd-item data-id="2"
.dd-handle.dd-nodrag
span.pull-right
= link_to t('folders', :default =&gt; t("helpers.links.folders")), new_asset_folders_path(parent_id: folder.id), :class=&gt;'btn btn-outline btn-info btn-xs',
'
= link_to t('files', :default =&gt; t("helpers.links.files")),  new_asset_folder_asset_path(folder), :class =&gt; 'btn btn-outline btn-info btn-xs',
span.label.label-info
i.fa.fa-folder
= folder.name
= render "actions", folder:folder
- unless params[:action] == "new"
.row
.hr-line-dashed
.form-group
.col-sm-4.col-sm-offset-1
= link_to new_asset_folder<span class="helper">_path</span>(parent_id: @folder.id), :class=&gt;'btn btn-primary' do
i.fa.fa-plus
i.fa.fa-plus
'
= I18n.t(:new, scope: 'helpers.submit', model: model_class.model_name.human)

app/controlers/asset_folders_controller.rb  #index

def index
@folders = AssetFolder.roots
@folder = params[:parent_id] ? AssetFolder.find(params[:parent_id]) : AssetFolder.first
respond_with(@folders)
end

app/views/asset_folders/new.html.slim

= simple_form_for @folder, :html =&gt; { :class =&gt; "form-horizontal", id: "my-awesome-dropzone" }, wrapper: :horizontal_form, wrapper_mappings: { check_boxes: :horizontal_radio_and_checkboxes, radio_buttons: :horizontal_radio_and_checkboxes, file: :horizontal_file_input, boolean: :horizontal_boolean } do |f|
= f.input :name
= f.input :parent_id, as: :hidden, input_html:{value: f.object.parent.try(:id)}
= f.input :parent, as: :string, input_html:{value: f.object.parent.try(:name)}, disabled: true
button.btn.btn-white data-dismiss="modal" type="button"  Close
= f.button :submit, t(:save), :class =&gt; 'btn btn-primary'

app/controlers/asset_folders_controller.rb  #new

def new
  @folder = AssetFolder.new(parent_id: params[:parent_id])
  respond_with(@folder)
end

app/controlers/asset_folders_controller.rb  #create

def create
  @folder = AssetFolder.new(asset_folder_params)
  flash[:notice] = 'Imentore::AssetFolder was successfully created.' if @folder.save
  @folders = AssetFolder.roots
  respond_with(@folder, location: admin_asset_folders_path)
end

Screen Shot 2015-11-22 at 18.31.18.png

Need more information please let me known or if this helped you.
Breno