2011-06-17

ActiveScaffoldでファイルアップロード

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ActiveScaffoldで管理しているモデルにファイルアップロード機能をつけたいと思ったわけです。

なんとActiveScaffoldでは、ファイルアップロードを使えるようにするfile_columnプラグインを利用できるようにすれば
勝手にファイルアップロードの画面が現れるのです。
http://wiki.activescaffold.com/wiki/published/FileColumnBridge

というわけで、file_columnプラグインを使えるようにします。

インストールは以下で。
script/plugin install http://filecolumn.googlecode.com/svn/tags/file_column

でも、2.3.11では、
uninitialized constant FileColumn::ClassMethods::Inflector
というエラーがでて動きませんでした。

なので
vender/plugins/file_column/lib/file_column.rb
のエラー発生部分を以下のように修正しました。
def file_column(attr, options={})
  options = DEFAULT_OPTIONS.merge(options) if options
      
  my_options = FileColumn::init_options(options, 
#                                        Inflector.underscore(self.name).to_s,
                                        ActiveSupport::Inflector.underscore(self.name).to_s,
                                        attr.to_s)
      
  state_attr = "@#{attr}_state".to_sym
  state_method = "#{attr}_state".to_sym
これとは別に以下のサイトでも直し方が紹介されています。
http://d.hatena.ne.jp/aki-s-119/20081201/1228168584

さらにデフォルトだと、日本語ファイル名は使えないので、
vender/plugins/file_column/lib/file_column.rb
の一部をいじりました。
def self.sanitize_filename(filename)
  filename = File.basename(filename.gsub("\\", "/")) # work-around for IE
#  filename.gsub!(/[^a-zA-Z0-9\.\-\+_]/,"_")
  filename.gsub!(/[^\w\.\-\+_]/,"_")
  filename = "_#{filename}" if filename =~ /^\.+$/
  filename = "unnamed" if filename.size == 0
  filename
end
以下のサイトを参考にさせていただきました。
http://www.kestrel.jp/modules/tinyd04/content/index.php?id=4

で後は、file_columnを使うことをモデルに記載してやればOKです。
以下の例では、foosテーブルのfilenameカラムにアップロードしたファイルの情報を格納して
実際にはpublic/uploadディレクトリの下にアップロードしたファイルが格納されます。
class Foo < ActiveRecord::Base
  file_column :filename, :web_root => "upload/",
                         :root_path => File.join(RAILS_ROOT, "public", "upload")
end

他にfile_columnに関しての情報は、以下が参考になります。
http://gdgdlog.net/log/show/227

後は、Fooモデル用のActiveScaffoldの画面を用意すれば、勝手にfilenameカラムがファイルアップロードのものになります。

私の環境では一度アップロードしたファイルを別のファイルに更新しようとするには一度、削除してからアップロードしないとダメでしたが、楽チンさを考えたらそれぐらいはよしです。

ActiveScaffoldステキです。


2011/6/24 追記
Railsアプリが
http://www.xxx.jp/
のような感じであれば上記だけで問題ないのですが、
専用のディレクトリの下で以下のような感じでやりたいとき、もうちょっとやることがあります。
http://www.xxx.jp/aaa/
アップロードはできるけど、ダウンロードがaaaを配慮してくれないのでできない情況です。

なのでActiveScaffoldとfile_columnそれぞれにちょっと手をいれます。

まずはActiveScaffoldは以下のファイルを以下のように変更します。
vendor/plugins/active_scaffold/lib/bridges/file_column/lib/list_ui.rb
       def active_scaffold_column_download_link(column, record, label = 
nil)
         return nil if record.send(column.name).nil?
         label||=as_(:download)
-        link_to( label, url_for_file_column(record, column.name.to_s), :popup => true)
+        link_to( label, url_for_file_column(record, column.name.to_s, {:absolute => true}), :popup => true)
       end

       def active_scaffold_column_thumbnail(column, record)

file_columnは以下のファイルを以下のように変更します。
vendor/plugins/file_column/lib/file_column_helper.rb
     return nil unless relative_path

     url = ""
-    url << request.relative_url_root.to_s if absolute
+    url << ActionController::Base.relative_url_root.to_s if absolute
     url << "/"
     url << object.send("#{method}_options")[:base_url] << "/"
     url << relative_path


2012/3/12 追記
Rails3.0では、ActionController::Base.relative_url_rootが使えなくなっているのでfile_columnは以下のように変更します。
vendor/plugins/file_column/lib/file_column_helper.rb
    url = ""
-   url << request.relative_url_root.to_s if absolute
-   url << "/"
+   url << root_url
    url << object.send("#{method}_options")[:base_url] << "/"
    url << relative_path


コメントを投稿