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
初期化
Photo.config.base_path = "/Library/WebServer/Documents" Photo.config.base_url = "http://localhost" Photo.config.no_image_filename = File.join( "/images/thumbs", "noimg.gif")
ただし、上にも書いたように、development環境で動作しているときは、アプリケーションの各クラスはリクエスト毎にロードされるので、
この初期化ファイルをモデル側で明示的に読み込まないといけないということになってしまっている。
結果
urlは
たとえば、以下のようになる。
http://localhost/photos/0000/0013/hoge.jpg
格納場所は
たとえば、以下のようになる。
/Library/WebServer/Documents/photos/0000/0013/hoge.jpg