Hobo with Paperclip - storage to db column.

Originally written by dziesig on 2011-01-05.

After installing Paperclip, getting it to work, and searching for the uploaded data I decided to RTM and found that I had two choices, storage on the file system (the default) or storage to s3. For business reasons (and the desire to eventually host on Heroku) I needed the data storage in the appropriate db tables.

Kevin found http://patshaughnessy.net/2009/2/19/database-storage-for-paperclip for me (I never thought to Google for it). Pat Shaughnessy did a really good implementation for Rails 3.0 which I used in place of the original paperclip. After a few issues, I got it working on Ralis 3.0, Hobo 1.3, as follows:

First install the plain-vanilla paperclip and get it working (use the default file system storage for simple installation) so you are starting from a known good condition.

Then

Edit Gemfile

gem 'paperclip',  :git => 'git://github.com/patshaughnessy/paperclip.git'

I put this just after the hobo line:

gem "hobo", ">= 1.3.0.pre25"

Then

sudo bundle install

In my case, this overwrote the existing plain-vanilla paperclip with Pat’s version.

Edit the model (in my case agent_documents.rb) adding/changing only two lines:

document_file	:binary # in the field definition block

has_attached_file :document, :storage => :database #THIS DID NOT WORK AT FIRST!

hobo g migration … THIS FAILED.

There is a chicken vs. egg problem here. The has_attached_file line is processed before the document_file :binary field declaration which leads to an undefined method error. The solution is to first comment out the , :storage => :database, then

hobo g migration

This time it works. Now un-comment “, :storage => :database”, restart your server and have fun uploading attachments.

Now for the download:

Edit the controller (in my case agent_documents_controller.rb), adding:

downloads_files_for :agent_document, :document

the first argument is the name of the model, the second is the attachment name as generated by paperclip.

Edit routes.rb, adding:

match 'agent_documents/documents/:id' => 'agent_documents#documents' 

at the appropriate priority level (mine was low so I put it at the end).

Lastly, insert the link in your appropriate dryml file. In my case, I added it to views/agent_documents/show.dryml:

<nav-item-external href="#{this.document.url}">View Document</nav-item-external>

or

<a-external href="#{this.document.url}">View Document</a-external>

My memory is going. I created (plagiarized and modified I think) the nav-item-external tag, but forgot about it, so anyone who implements this will get an error. The definition (and the similar a-external tag) is:

<def tag="nav-item-external" attrs="name">
  <% body = parameters.default
     body = h(this.to_s) if body.blank?
     name ||= body.gsub(/<.*?>/, '').strip
   -%>
  <li class="#{'current' if (c = scope.current_navigation) && c.downcase == name.downcase}"
    merge-attrs="&attributes - (attrs_for(:a)+['target'])">
  <a onclick="window.open(this.href);return false;" merge-attrs="&attributes & (attrs_for(:a)+['target'])"><%= body %></a>
  </li>
</def>


<def tag="a-external" attrs="name">
  <% body = parameters.default
     body = h(this.to_s) if body.blank?
     name ||= body.gsub(/<.*?>/, '').strip
  -%>
    <a onclick="window.open(this.href);return false;" merge-attrs="&attributes & (attrs_for(:a)+['target'])"><%= body %></a>
</def>

In my case, I put both of these in app/views/taglibs/internet_nav.dryml


Edit this page