Skip to content

Instantly share code, notes, and snippets.

@t0nylombardi
Created September 22, 2017 16:15
Show Gist options
  • Save t0nylombardi/544c70003e20428990420608d139d8e5 to your computer and use it in GitHub Desktop.
Save t0nylombardi/544c70003e20428990420608d139d8e5 to your computer and use it in GitHub Desktop.
Multiple File attachment

Models

Lessons Model

class Lesson < ApplicationRecord
  belongs_to :user
  has_many :attachments, dependent: :destroy
  accepts_nested_attributes_for :attachments
end

Attachment Model

class Attachment < ApplicationRecord
  belongs_to :lesson, optional: true
  include AttachmentUploader::Attachment.new(:media)
end

Controllers

Lessons controller

Class LessonsController < ApplicationController
  # truncated for brevity.
  
  def new
    @lesson = current_user.lessons.build
  end


  def create
    @lesson = current_user.lessons.build(lesson_params)
    
    respond_to do |format|
      if @lesson.save

        if params[:media]
          params[:media].each { |media|
            @lesson.attachments.create(media_data: media)
          }
        end

        format.html { redirect_to @lesson, notice: 'Lesson was successfully created.' }
        format.json { render :show, status: :created, location: @lesson }
      else
        puts "\n\n\n#{@lesson.errors.full_messages.to_sentence}\n\n\n"
        format.html { render :new, notice: @lesson.errors }
      end
    end

  end

 
 
  private
    
    def set_lesson
      @lesson = Lesson.find(params[:id])
    end

    def lesson_params
      params.require(:lesson).permit(
        :title, 
        :content, 
        :document, 
        :category_id,
        :pinned, 
        :bootsy_image_gallery_id, 
        attachments_attributes: {media: []},
      )
    end

end

Attachment Controller

class AttachmentsController < ApplicationController
  before_action :set_attachment, only: [:edit, :update, :destroy]

  def create
    @attachment = Attachment.new(attachment_params)
    @attachment.save
  end


  private
    
    def set_attachment
      @attachment = Attachment.find(params[:id])
    end

    def attachment_params
      params.fetch(:attachment, {})
    end
end

ERB

_form.html.erb

<%= @lesson.errors.full_messages.first if @lesson.errors.any? %>
<%= form_for @lesson do |f| %>
<div class="control-group">
  <%= f.label :title %>
  <div class="controls">
    <%= f.text_field :title, required: true %>
  </div>

  <div>
    <%= f.label :content %>
    <%= f.bootsy_area :content, editor_options: { html: false }, rows: "20", cols: "100" %>
  </div>

  <div>
    <%= f.label 'File under at least one class' %>
    <%= f.collection_select :category_id, Subject.all, :id, :name, { promt: "Choose a Class" } %>
  </div>

  <div>
    <%= f.label :pinned %>
    <%= f.label :pinned, "Yes", value: "Yes"  %>
    <%= f.radio_button :pinned, true%>
    <%= f.label :pinned, "No", value: "No" %>
    <%= f.radio_button :pinned, false, checked: true %>
  </div>
  <hr>

  
    <div>
      <%= f.label 'Or Upoad a file' %>
      
      <%
        ######################
        # This is where I have the attachment file field. 
        ######################      
      %>
      
      <%= file_field_tag "media[]", type: :file, multiple: true %>
      
    </div>
  
  <br>
    <%= f.submit nil %>
    <%= link_to 'Cancel', lessons_path%>

  <div class="form-actions btn-a">
    <%= link_to 'Cancel', lessons_path, class: "btn btn-default" %>
  </div>

<% end %>

Routes

Rails.application.routes.draw do
  mount AttachmentUploader::UploadEndpoint => "/attachments/upload"
  
     
  resources :lessons do
    member do
      put "like",     to: "lessons#upvote"
      put "dislike",  to: "lessons#downvote"
    end
    resources :comments
    resources :attachments
  end
  
  root 'static#index'

end

JS

$(document).on("turbolinks:load", function () {
  $("[type=file]").fileupload({
    add: function (e, data) {
      data.progressBar = $('<div class="progress" style="width: 300px"><div class="progress-bar"></div></dov>').insertAfter("#file-upload");
      var options = {
        extension: data.files[0].name.match(/(\.\w+)?$/)[0],
        _: Date.now() // revent caching
      }

      $.getJSON("/attachments/upload/cache/presign", options, function (result) {
        data.formData = result['fields'];
        data.url = result['url'];
        data.paramName = "file";
        data.submit();
      });
    },
    progress: function (e, data) {
      var progress = parseInt(data.loaded / data.total * 100, 10);
      var percentage = progress.toString() + '%';
      data.progressBar.find(".progress-bar").css("width", percentage).html(percentage);
    },
    done: function (e, data) {
      console.log("done", data);
      data.progressBar.remove();

      var document = {
        id: data.formData.key.match(/cache\/(.+)/)[1],
        storage: 'cache',
        metadata: {
          size: data.files[0].size,
          filename: data.files[0].name.match(/[^\/\\]+$/)[0],
          mime_type: data.files[0].type
        }
      }

      form = $(this).closest("form");
      form_data = new FormData(form[0]);
      form_data.append($(this).attr("name"), JSON.stringify(document))

      $.ajax(form.attr("action"), {
        contentType: false,
        processData: false,
        data: form_data,
        method: form.attr("method"),
        dataType: "json",
        success: function(response) {
          var $img = $("<img/>", { src: response.image_url, width: 400 });
          var $div = $("<div/>").append($img);
          $("#photos").append($div);
        }
      });
    }
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment