attachment_fuプラグインの保存先を変更

前回、attchment_fuでとりあえず画像アップロードをしてみたが、

今回、保存先と画像を参照するurlを変更する実装を行っていみる。
アプリケーションとは別のディレクトリで画像を管理したいということと、
railsではなくapacheで画像のリクエストを処理させるということが目的。
対象としたrailsは2.0.2。


基本としては、画像をあつかうmodelでattachment_fuのファイルストレージ(file_system_backend.rb)で定義されているメソッドのオーバーライドすることと、
初期化スクリプトを使ってパスとurlの設定を行えるようにすることにより対応。

モデルの定義

今回、Photoというモデルを画像を扱うモデルとして作成。以下のような実装を行う。

Configというネストしたクラスを定義。

Configというネストしたクラスを定義。さらにモデル側にそのインスタンス参照するためのconfigというスタティック属性を定義。
ここに、ベースとなるurl,格納ディレクトリのベース、対応する画像が無いときに表示する画像の相対パスを定義。
config/initializer/photo.rbで各属性へ値を設定することを想定した定義である。
なお、Configをインスタンス化した後ででconfig/initializer/photo.rbをloadしているのは、development環境でrailsを起動している場合、
このモデル自体が、リクエスト毎に再読み込みされるので、この初期化スクリプトも毎回読み直してやる必要があるから。

Configされた属性を返すメソッドをモデルに定義

上記したConfigの属性を参照するメソッド(base_url,base_path, no_image_filename)を定義。属性のアクセスの記述を簡易にする程度の目的。

full_filenameをオーバーライド

attachment_fuのファイルストレージ(file_system_backend.rb)で定義されているfull_filenameをオーバーライド。
このメソッドは、ファイルを格納するファイル名をフルパスで返すもの。Configの属性で定義したベースパス下のパスになるよう定義。

public_filenameをオーバーライド

attachment_fuのファイルストレージ(file_system_backend.rb)で定義されているpublic_filenameをオーバーライド。
これは、画像を参照するurlを返すメソッド。Configの属性で定義したベース以下のurlになるよう定義。

#
# 商品画像のモデル
# attachment_fuプラグインを使用して、アップロード、画像表示に対応
#
class Photo < ActiveRecord::Base

  # モデルのConfiguration情報を格納
  # 以下の属性を含む
  # <tt>base_path</tt> - 画像を配置するベースパス 
  # <tt>base_url</tt> - 画像を参照するurlのベース
  # <tt>no_image_filename</tt> - No image画像の相対パス
  class Config
    attr_accessor :base_path, :base_url, :no_image_filename
    def initialize
      puts "init"
      @base_url = "http://localhost"
      @base_path = '/var/www'
      @no_image_filename = File.join( "/images/thumbs", "noimg.gif")
    end
  end


  # モデルのconfiguratioのインスタンス
  @@config = nil
  def Photo.config
    if @@config.nil? then  
      @@config = Photo::Config.new 
      load(File.join(RAILS_ROOT, 'config','initializers', 'photo.rb'  ))
    end
    @@config
  end

  # attachment_fuのオプション設定
	has_attachment :content_type => :image, 
                   :storage => :file_system, 
                   :max_size => 1.megabyte,
                   :thumbnails => { :thumb => '100x100>', :small => '50x50>' },
                   :path_prefix => "photos"
  
  # アップロード時のvalidationをすることを指定
  validates_as_attachment

  
  # No image画像の相対パス
  def self.no_image_filename
    @@no_image_filename = Photo.config.no_image_filename
  end
  
  
  # 画像を配置するベースパス
  # Used as the base path that #public_filename strips off full_filename to create the public path
  def base_path()
    @base_path ||= Photo.config.base_path
  end
  
  # 画像を参照するurlのベース
  def base_url()
    @base_url ||= Photo.config.base_url
  end
  
  # Gets the public path to the file
  # The optional thumbnail argument will output the thumbnail's filename.
  def public_filename(thumbnail = nil)
    base_url + full_filename(thumbnail).gsub(%r(^#{Regexp.escape(base_path)}), '')
  end
  
  # Gets the full path to the filename in this format:
  #
  # <base_path>/<path_prefix>/<画像IDの5から8桁>/<画像IDの1から4桁>/<画像名>のようになる。
  #
  # override from Technoweenie::AttachmentFu::Backend::FileSystemBackend
  def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix].to_s
    File.join(base_path, file_system_path, *partitioned_path(thumbnail_name_for(thumbnail)))
  end

    
end

初期化

/initializer/photo.rbでConfigurationを行う。

Photo.config.base_path = "/Library/WebServer/Documents"
Photo.config.base_url = "http://localhost"
Photo.config.no_image_filename = File.join( "/images/thumbs", "noimg.gif")

/initializerのファイルはrailsの起動時に読み込まれることになっている。
ただし、上にも書いたように、development環境で動作しているときは、アプリケーションの各クラスはリクエスト毎にロードされるので、
この初期化ファイルをモデル側で明示的に読み込まないといけないということになってしまっている。

結果

urlは//<画像IDの5〜8桁>/<画像IDの5〜8桁>/<ファイル名>となる。
たとえば、以下のようになる。
http://localhost/photos/0000/0013/hoge.jpg

格納場所は//<画像IDの5〜8桁>/<画像IDの5〜8桁>/<ファイル名>となる。
たとえば、以下のようになる。
/Library/WebServer/Documents/photos/0000/0013/hoge.jpg