Thought Paperclip offers storage path and url customization, however, sometimes it just cannot satisfy some situation. For example, when you have a complex path/url generation logic that must be handle outside the model and you don't know the path/url until the last moment before creating model object. In this case, maybe the only way is "PASS" them into the model object, just like passing arguments in C/C++ or Java.

I tried few ways to solve this problem, here I'm going to show you what's NOT gonna work and why and finally what's gonna work it out.

Say there're 2 dependent models
A -> B
which means A owns B. Assume A and B are both literally singular. B has attachement called file. The attachement's path and url will be calculated in controller, in this case, not model .

#In some_controller.rb

class SomeController < ApplicationController
  def some_method
    @a = A.create!
    b =
    b.file =
    b.store_path = path #string

    b.store_url  = url  #string!
    puts b.file.path  # equals to path, no problem

    puts b.file.url   # equals to url, no problem


#In B.rb

class B < ActiveRecord::Base
# automatically generate setter and getters for @store_path and @store_url

# By the way, @store_path directly access the instance variable while self.store_path calls the getter method

attr_accessor :store_path, :store_url 

has_attached_file :file,
                  :path => :get_path
                  :url  => :get_url
  def get_path
  def get_url


It works. file was stored in path. Perfect. But when we retrieve from database, e.g.

# for example, in another_controller.rb

class AnotherController < ApplicationController
  def some_method
    b = B.find_by_id(params[:id]) 
    b.file.path # wrong, it becomes to paperclip's default path

    b.file.url  # wrong, it becomes to paperclip's default url


What the hell are these things happens! Go checkout your disk, file is exactly stored in the location. But you can't find them from the database.

The reason is: @store_path and @store_url are instance variables and they're just not exist in the new object initiated by B.find_by_id(params[:id]). Unless you assign values to them after you create a new object, or it will be nil, thus when you tried to access file.path or file.url, paperclip will send back default value of course. So you got file stored properly but cannot be accessed from database forever. The key for paperclip to use dynamically generated arguments is:

Just save the storage information in database.

It's pretty straight forward. Cost extra 2 columns, which is the price I really don't want to pay at the begining. But well... it's alright.

This phenomenant like the dangling object in C/C++, where a pointer is pointing to some object, then once the pointer's value changes, you could never get a way to access what it was pointed to -- the object.


comments powered by Disqus