Friday, February 10, 2012

From file_column to paperclip

At the time ClassroomParent was started, the file_column plugin was the state of art for uploads. Not only did it integrate nicely with rmagick, but there was also a bridge for active_scaffold.

But file_column has been left behind by many excellent plugins/gems, most notably, paperclip.

In 2008, Mark Cornick wrote an excellent blog on how to migrate from file_column to paperclip. For the most part, I have followed his instructions, though I split his single migration into several. 


One major hurdle I had to overcome was that my file storage path is dynamically generated. This is so I can better segregate one school's assets from another. 


Looking at the paperclip documentation, they state that the attributes associated with has_attached_file can accept a lambda, so I tried this on the :path attribute:


  :path => lambda { |attachment| "/system/#{attachment.instance.sub_domain}/:class/:id/:basename.:extension"


This worked for the path value, but when I tried to access the url value, I got the following error:


NoMethodError: undefined method `gsub' for #<Proc:0x000001058f79a0>
    from /Users/user/.rvm/gems/ruby-1.9.2-p180@classroom_parent/gems/paperclip-2.5.2/lib/paperclip/interpolations.rb:33:in `block in interpolate'
    from /Users/user/.rvm/gems/ruby-1.9.2-p180@classroom_parent/gems/paperclip-2.5.2/lib/paperclip/interpolations.rb:32:in `each'



Looking at the paperclip code, I could see the offending gsub statement, and it did not look easy to work around it. 


However, there was a little note, that I don't believe is echoed in the paperclip gems readme, that states that a symbol can be passed to the path attribute that references an instance method. Moving my code from the lambda to a public private method, and using that method name as the value passed to the path attribute worked like a charm. 


  :path => :path_to_file


  def path_to_file
    return "/system/#{sub_domain}/:class/:id/:basename.:extension"
  end


private
  def sub_domain
    ...code to get to the sub_domain of the school
  end

   

4 comments:

  1. Thanks for solution. It works for me.
    But I used a private method to return the path.

    ReplyDelete
  2. Prodis: That does make more sense. I have done the same and will edit the blog to match.

    ReplyDelete
  3. Thanks for this, I still had problems with gsub when using it for :path but found the interpolate solution works a charm http://stackoverflow.com/a/11067061/409023

    ReplyDelete