John Keith

Ruby. Rails. Launch Academy.

Simple File Uploads to Rails With Dragonfly

Gems are amazing. As a rookie developer, it is incredible to come into the Ruby/Rails community and discover the wealth of code that is available out there, packaged and ready to be used. I’d encountered and enjoyed open source software before, but it was not until I started writing code that I really came to appreciate what the concept means.

Take for instance file uploading with Rails. You can perform basic uploads using what Rails offers natively or you can choose from a multitude of gems (Paperclip, Carrierwave, Dragonfly, the list goes on) that add more advanced methods of uploading and storing files in your Rails app.

For the expense tracker I am currently working on, I selected Dragonfly. I’ll admit, I tried Paperclip first and I was unable to make it function correctly. My lack of success with Paperclip, however, was only half the reason I ended up with Dragonfly.

As I was envisioning document uploads in my app, I wanted the document (a receipt or invoice of a purchase) to become part of the Expenses table that I had already set up with a multitude of fields. With Paperclip, as far as I understood from the tutorials provided, it seemed like the documents would be set up as a separate model in the database, then associated with my current Expenses model. I can see advantages to the Paperclip approach (making all the documents easily accessible in one section of the database), but I wanted keep the relationships in this app as simple as possible, if only for my own sanity.

The great part about Dragonfly is it makes adding a :document column to your current model incredibly easy. The instructions below were what I did to install and integrate Dragonfly to upload documents when creating a new record in my Expense model.

First, I added Dragonfly to my gemfile and ran bundler.

gem 'dragonfly', "~>1.0.3"
$ bundle install

Then, in my app/models/expense.rb, I added an accessor for my document.

dragonfly_accessor :document

Back at the command line, I setup a migration to add a document column to my expenses model.

$ Rails generate migration AddDocumentToExpenses

Inside the migration document, I added two columns, one for the :document_uid and :document_name, per the Dragonfly wiki.

class AddDocumentToExpenses < ActiveRecord::Migration
  def change
    add_column :expenses, :document_uid, :string
    add_column :expenses, :document_name, :string
  end
end

Then came migrating the database.

rake db:migrate

Next was altering my app/views/expenses/_form.html.erb to include a field for file uploads.

<div class="field">
    <%= f.label :document %><br>
    <%= f.file_field :document %>
</div>

Then, inside my app/controllers/expenses_controller.rb, I added :document to the list of permitted parameters near the bottom.

def expense_params
    params.require(:expense).permit(:user_id, :date, :reseller, :item_or_service, :payment_form, :charged_to, :cost, :amount_from_budget, :notes, :document)
end

With the next step, I was unsure if this was the correct course to take. I was worried about my files being uploaded to the public folder, as I assumed anything in that area would be easily accessible from the outside. I created a directory in the root of my app called secure_storage, though I have no idea if that name is a complete misnomer. Then, I opened the config/initializers/dragonfly.rb and changed the default location for where files would be stored. Again, hopefully this will put them in a better location than the public directory, but I am not a hundred precent sure.

datastore :file,
  root_path: Rails.root.join('secure_storage/system/dragonfly', Rails.env),
  server_root: Rails.root.join('secure_storage')

Finally, I added a file link (with a condition to make sure it didn’t appear if no file was present with the record) on the app/views/expenses/show.html.erb.

<% if @expense.document %>
<p>
  <strong>Document:</strong>
  <%= link_to "File", root_url.chop + @expense.document.url %>
</p>
<% end %>

That, I believe, was all! You should now have a working file upload function, one that even lets you download the file too! If you try this and have trouble, let me know in the comments below.

Using Evernote With David Allen’s ‘Getting Things Done’ System

I’ve been using Evernote for a long time now and it has proven to be a fantastic system for storing information. That said, turning it into a system I can use to organize my life has been a Sisyphean experience. Over the years, my Evernote account has undergone a series of shakeups as I’ve tried out different organizational schemes, but each new system of handling notes, websites, and articles has left me feeling no more put together.

Part of our pre-work for Launch Academy has been to read a series of “brain hacking” books to get us ready for the start of the program. After diving into David Allen’s Getting Things Done, I think I may see a way to corral my ever-ballooning Evernote into a much more manageable and useful repository.

Currently, I open Evernote to a slew of notebook stacks and subnotebooks.

My current Evernote

While having many individual notebooks is a passable strategy, I’ve found that it becomes less and less useful the more notebooks you create. My count right now is over 50 and I think that might be 44 too many.

An overabundance of notebooks starts to cause problems when you try to send something Evernote from within an app (like a newsreader or through email), as it always becomes a question of how to categorize this piece of information. By default, my notes are routed into a folder I called _INCOMING. This has been a nice landing spot, but the vagueness of the name (or perhaps its linguistic proximity to “inbox”) has contributed to my lack of desire to sort through the massive flood of stuff that piles up in there.

In Allen’s book, he divides the organizational process into five stages: collect, process, organize, review, do. To reformat my Evernote to follow this system, I’m going to start by creating a _Processing folder and setting it as the default location for collecting everything that hits my Evernote. This will be the folder that I’ll take the time every other day to process the items from - to figure out “what they mean and what to do about them” (Allen).

From the processing folder, an item will have four places to go: into the NextSteps, Projects, Incubating, or Archives folder.

In the NextSteps folder will be all todo items, things that need to be done in the short term or short term actions that need to be taken in relation to longer term projects or goals.

In the Projects folder will reside all of the active ideas or projects that I’m working on at the moment. And, as in Getting Things Done, the term projects is defined in a different sense than we usually use, as “any desired result that requires more than one action step” (Allen).

The Incubating (I wanted to use a more active term than Allen’s “incubation”) folder will house the more lofty and long term items - app ideas, career goals, etc.

Lastly, in the Archives folder, I’m going to store everything that resides in my current notebooks. In other words, the Archives folder is essentially going to house everything that passes through my Evernote - it is the final destination of all information.

I think this is the key to any organizational system - there must be a logical, actionable flow of information through the system, including a final resting place where the inactive information may be stored and retrieved.

Since Evernote does such a great job with indexing and searching any and every piece of information inside your account, I feel that there is no need to employ the tagging feature, that it might only slow down the movement of information into and through the new system. I’m going to spend some time not using tagging and see how it goes.

Allen emphasizes the important of reviewing the items in your organizational system at least once a week. I would love if it was possible to create a recurring reminder in Evernote that would alert me when I should review the information I have in each of my actionable folders (NextSteps, Projects, and Incubating), but for now perhaps a weekly calendar alert will suffice.

Build What You Use as a Way to Learn

I can’t remember where I read it, but recently I came across the advice that one of the best ways to practice programming is to recreate the type of applications you use everyday. No need to make them flashy, simply implement their core features in order to achieve the same results.

I decided to give it a try today and build a tiny todo app in Ruby. I wanted to write the app keeping in mind the directives from Sandi’s Metz’s Practical Object-Oriented Design in Ruby.

“Remember that a class should do the smallest possible useful thing. That thing ought to be simple to describe. If the simplest description you can devise uses the word “and,” the class likely has more than one responsibility.​” - Metz

While it ended up that my app only had one class, I tried to follow in the spirit of the quote above by keeping my methods as focused as possible. I also tried to heed her advice to stave off design decisions for as long as possible - an interesting strategy that had me trying to store all completed and incomplete todos in the same file. I quickly realized, though, that this was an inefficient way of doing things, since my completed items list would (hopefully) be a far larger file than my active items list and there is no reason to load that large file every time the app is opened.

There is one little quirk that I can’t seem to shake: when you mark a todo as finished, the item is removed from the activelist.txt file, but is not added to the completelist.txt file until you close the program. I’m sure it has something to do with the file opening modes I selected, but I can’t figure out why I am able to modify and then view the modifications done to activelist.txt while in the app, but not do the same with completelist.txt.

In the end, this was a great way to get practice using the File and IO classes of Ruby and exploring their methods. Not to mention, I get a pretty nifty little command line todo list manager (which I’ll stick in Dropbox for easy access) out of it!

require 'rbconfig'

class Todo
    def clear_screen
        host_os = RbConfig::CONFIG['host_os']

        case host_os
            when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
                system "cls"
            when /darwin|mac os|linux|solaris|bsd/
                puts "\e[H\e[2J"
        end
    end

    def open_app
        view_all
    end

    def view_all
        clear_screen

        list_read = read_active_list
        
        puts "------INCOMPLETE------\n\n"
        list_read.each do |line|
            puts line
        end
        puts "\n----------------------"

        choose_action
    end

    def read_active_list
        list = File.open("activelist.txt","a+").readlines
    end

    def choose_action
        puts %/
        What would you like to do with your list?
        1. Add a todo
        2. Mark complete
        3. View incomplete
        4. View completed
        5. Exit/

        choice = gets.chomp.downcase

        case choice
            when "1" then input_todo
            when "1." then input_todo
            when "add" then input_todo
            when "add todo" then input_todo
        
            when "2" then mark_done
            when "2." then mark_done
            when "mark" then mark_done
            when "mark done" then mark_done

            when "3" then view_incomplete
            when "3." then view_incomplete
            when "view incomplete" then view_incomplete
            
            when "4" then view_complete
            when "4." then view_complete
            when "view completed" then view_complete

            when "5" then return
            when "5." then return
            when "exit" then return

            else
                p "Not a valid choice"
                choose_action
        end
    end

#ask for todo
    def input_todo
        puts "\nEnter your new todo:"
        todo = gets.chomp
        add_todo(todo)
        view_all
    end

#write method
    def add_todo(todo)
        File.open("activelist.txt", "a") { |f| f.write "#{todo}\n" }
    end

#mark done method
    def mark_done
        clear_screen

        list_read = File.open("activelist.txt","a+").readlines

        puts "------INCOMPLETE------\n\n"
        list_read.each_with_index do |line, index|
            puts "#{index + 1}. " + line
        end
        puts "\n----------------------"

        puts "\nWhich todo do you want to mark complete? (Type the number or zero to cancel)."
        
        choice = gets.chomp.to_i

        File.open("activelist.txt", "w") do |f|
            list_read.each_with_index do |line, index|
                if (index + 1) == choice 
                    add_to_complete_list line
                else
                    f.write "#{line}"
                end
            end
        end

        view_all
    end

    def add_to_complete_list line
        File.open("completelist.txt", "a").write "#{line}"
    end

    def view_complete
        clear_screen

        complete_list = File.open("completelist.txt", "a+").readlines

        puts "------COMPLETED------\n\n"
        complete_list.each do |line|
            puts line
        end
        puts "\n---------------------"

        choose_action
    end

    def view_incomplete
        view_all
    end
end

my_todo_list = Todo.new

my_todo_list.open_app

Image Hosting for a Heroku Octopress Site

Since Heroku only allows for 300 MB of storage for their free tier of hosting, it makes sense to store the images for an Octopress site in a separate location. Previously, I used Flickr for a few posts, but the process of uploading the files and hunting down the embed link was tiresome.

The better way, it seems, is to use Google Drive, despite the fact that Google doesn’t provide an easy way to embed either. What makes using Google Drive much friendlier than Flickr, however, is a site called gdURL.

With gdURL, all you need to do is share an image file on Google Drive, change the privacy settings to “Anyone who has the link can view”, then run the link Google Drive provides you through the gdURL service and you receive a tidy, bite-sized link for embedding your image.

For instance, I used gdURL in the following line to link to a picture of this site’s new theme.

![So Fresh and So Green](http://gdurl.com/i4Wr)​

So Fresh and So Green

Quick, easy, and keeps the size of your Octopress repo down.

New Look for the Blog

I’ve been meaning to build an Octopress theme since I put this site up back in January. To start with, this blog was using the Whitespace theme, which was a fantastic starting point, but I wanted to create something with a little more…color!

After reading Vladi’s post about creating a theme called Readify, I was inspired to take a shot at it.

To that end…here’s what I’ve got so far. The code is available here, should you want to install it on your own Octopress! I reworked the Classc theme to include a few basic changes that hopefully will make it more readable and usable.

  • Larger font and line heights
  • Fixed navbar that becomes unfixed on mobile devices
  • Green everywhere!

Finding Middle Ground With Middleman

For a while, I’ve been wondering - where is the better way of building static sites? I’ve made a ton of stuff working off of Bootstrap templates and Wordpress themes, but I also really love creating sites without all the mess of those big frameworks. I want to hand code sites to keep learning about the presentational side of web development, but an environment like Rails is not ideal for such explorations. Even the much more manageable Sinatra is only a little better, as I feel like my focus when building something in Sinatra is split evenly between the front-end and back-end.

That said, after finding and playing with Middleman, I believe it provides the perfect way to focus on the front-end of things without sacrificing the power of HAML, SASS and the like. The LiveReload extension is also amazing - it is incredible how small efficiencies make all the differences when writing and testing out new ideas.

I was really thrilled when I managed to figure out how to insert Markdown files into a HAML template built in a Middleman project.

.main-contain
  .pure-g-r
    .pure-u-1-2
      %h1 Hello folks.
    .pure-u-1-2
      %p What up?
      :markdown
        #{File.read(File.join(File.dirname(__FILE__), "test.md"))}

The code is nothing special, but being able to read a file of Markdown text and insert it into my template was pretty exciting. I’m planning to use this trick to create a text-heavy site that keeps its content as separate from the presentation as possible by inserting all the large chunks of text as Markdown files into templates.