2010年11月21日

Herokuに画像をアップロードする Rails 3 + Paperclip + Amazon S3

Heroku上で作成中のアプリに画像をアップロードできる機能を追加したいと思い挑戦してみました。
    調査結果:
  • HerokuはRead-onlyなので、Herokuのファイルシステムには画像はアップロードできなさそう
  • 代わりにHerokuの公式サイトではAmazon S3をストレージとして利用することを推奨している
  • また同じページにはAttachment-Fu か Paperclipプラグインを利用することが簡単だろうとのこと
  • 実際にHeroku + Paperclip + Amazon S3を利用した構築方法が以下のサイトで公開されている
    http://webtempest.com/how-to-allow-image-uploads-in-rails-on-heroku/
ということで、私もHeroku + Paperclip + Amazon S3で作ってみたいと思います。

Amazon S3
まず気になる利用料。せっかくHerokuを使って無料アプリを作っているので、あまりお金をストレージにつぎ込みたくないというのが本音です。で、Amazonのページで確認すると、
  • ストレージ: 月額料金 $0.140/GB
  • 低冗長化ストレージ: 月額料金 $0.093/GB
  • データ転送:全てのデータ受信: $0.100 /GB
  • リクエスト: $0.01/1,000リクエスト
という何とも信じられない親切な値段設定(2010年11月21日現在)。サイトの人気が出ない限りは1GBにたどり着くのに何年もかかるだろうから毎月100円以下で当面はすみそうです。

ということで、さっそく申込みしてみます。
同じページにある「Amazon S3の利用を申し込む」ボタンを押します。
ログインページでログインします。
次のページで値段を確認して、クレジットカード情報を入力します。
住所を確認します。
最後にサマリーページが表示されるので、ここで確認をして「Complete Sign Up」ボタンを押すと申し込みが完了です。
しばらくするとAmazonからメールが届くので、そこに書いてあるリンクをクリックしてページにログインすると、利用するために必要なAccess Keysなどの情報が確認できます。
これで基本的な申し込みは完了しました。

S3にアクセスするためにFireFoxのプラグインであるAmazon S3 Organizer(S3Fox)をインストールします。
S3Foxの利用方法は動画で公開されています。英語だけど動画なのでわかりやすいです。
FireFoxを再起動後、ツールメニューのS3 OrganizerをクリックするとS3 Organizerが起動するので、Manage Accountsボタンをクリックし、先ほどAmazonで入手した情報を入力します。
さっそく試しにファイルをアップロードしてみようとしたところ、Bucketの選択ダイアログが開いたので、いったんキャンセルをします。
Create Bucket/Directoryボタンを押してBucketを作成します。Bucketの名前にはいろいろなルールがあるようなのですが、S3の中でユニークである必要があるようです。そしてここで付けた名前がそのままファイルにアクセスする際のURIに利用されるので、それを意識して名前を付けるのが良いです。
先ほど作成したBucketにファイルをUploadしてみます。Uploadに成功したらファイルのアクセス権を設定します。ファイルの上で右クリックして、Edit ACLを選択します。EveryoneのReadにチェックしてみました。確認のために再びファイルの上で右クリックして、Copy URL to Clipboardをクリックし、ブラウザのアドレスバーに貼り付けます。無事ファイルが表示されました。
以上でS3の設定が完了です。

なおS3へのアクセス方法やBucketについては、こちらのエントリーが参考になります。
http://www.labnol.org/internet/tools/amazon-s3-simple-storage-service-guide/3889/
http://www.labnol.org/internet/tools/amazon-s3-buckets-tutorial/3890/


Paperclip
ここからはPaperclipとS3を連携させてみたいと思います。
まずはRailsのアプリ(s3paperclip)を作成します。
$ rails new s3paperclip
$ cd s3paperclip

アプリルートのGemfileに以下の二行を追加し(今回はDBにsqlite3を利用)、インストールを行います。
gem 'sqlite3-ruby'
gem 'paperclip'

$ bundle install

Productモデルを作成し、画像を持つことにします。画像はphotoという呼び名にしておきます。
$ rails g scaffold product name:string
Productモデルを以下のように編集します。
class Product < ActiveRecord::Base 
has_attached_file :photo,
:styles => {
:thumb => "100x100",
:medium => "200x200",
:large => "600x400"
}
end
さらにS3に保存するために以下のように編集します。
class Product < ActiveRecord::Base 
has_attached_file :photo,
:styles => {
:thumb => "100x100",
:medium => "200x200",
:large => "600x400"
},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => ":attachment/:id/:style.:extension"
end
#{RAILS_ROOT}/configに、s3.ymlというファイルを作成し以下のように記述します。
development:
bucket: myappdevelopment
access_key_id: your key
secret_access_key: your key

test:
bucket: myapptest
access_key_id: your key
secret_access_key: your key

production:
bucket: myapp
access_key_id: your key
secret_access_key: your key
※bucketやyour keyの部分は環境に合わせて定義が必要です。

gemファイルにAmazon S3用の記述を追加します。
gem 'aws-s3'
インストールします。
$ bundle install

DBに画像の情報を記録できるようにProductsテーブルを書き換えます。
これはマイグレーション用のスクリプトを作成して行います。
$ rails g migration add_photo_columns_to_product
作成されたdb/migrate/(Date)_add_photo_columns_to_product.rbを以下のように編集します。
class AddPhotoColumnsToProduct < ActiveRecord::Migration
def self.up
add_column :products, :photo_file_name, :string
add_column :products, :photo_content_type, :string
add_column :products, :photo_file_size, :integer
add_column :products, :photo_updated_at, :datetime
end

def self.down
remove_column :products, :photo_file_name
remove_column :products, :photo_content_type
remove_column :products, :photo_file_size
remove_column :products, :photo_updated_at
end
end
マイグレーションをします。
$ rake db:migrate

formビューを書き換えます。
(1行目を書き換え)
<%= form_for @product , :html => { :multipart => true } do |f| %>

(form内に追記)
<%= f.file_field :photo %>

showビューを書き換えます。
<%= image_tag @product.photo.url %>
<%= image_tag @product.photo.url(:medium) %>
<%= image_tag @product.photo(:thumb) %>
<%= image_tag @product.photo(:large) %>

gitにコミットします。
$ git init
$ git add -A
$ git commit -m "new app"

Herokuにアプリを配置します。
$ git push heroku master

DBをマイグレートします。
$ heroku rake db:migrate

以上で画像ファイルがHerokuにアップロードできるようになりました。
注意点としては、ローカルの開発環境にImgamagicがインストールされていないと、正常に動作しない点ですね。Heroku上では正常に動作します。

追記:
Windowsで動作できるようにRails 3 WindowsでPaperclipを使えるようにするを書きました。
posted by まーつん at 22:02| Comment(0) | TrackBack(0) | Ruby on Rails | このブログの読者になる | 更新情報をチェックする

2010年11月20日

Rails link_toメソッドで指定するパス

railsでリンクを作成する場合はlink_toメソッドを使うことになるわけなのですが、パスの指定方法がわからなかったので調べてみました。

link_to
使い方: link_to(テキスト, パス, [HTMLオプション])
サンプル: <%= link_to '製品の登録', new_product_path %>
サンプルの結果: <a href="/products/new">製品の登録</a>

上記の例では"/products/new"というパスを導くために、new_product_pathと書いてあるわけです。
今回わからなかったのは、どうすれば"/products/new"とnew_product_pathを関連付けできるのかという点です。

関連付けの調べ方:
例えば"/users/sign_in"に関連付けされたパスを調べたいとした場合、コマンドプロンプトで$ rake routesを入力します。
そして、表示結果から"/users/sign_in"を含む情報を見つけます。
new_user_session GET    /users/sign_in(.:format) 
{:action=>"new", :controller=>"devise/sessions"}
これで"new_user_session"が関連付けされていることがわかります。

後はlink_toを書くときに、"new_user_session"に"_path"と付ければOKということになります。
例: <%= link_to 'サインイン', new_user_session_path %>
例の結果: <a href="/users/sign_in">サインイン</a>
タグ:Rails
posted by まーつん at 18:25| Comment(1) | TrackBack(0) | Ruby on Rails | このブログの読者になる | 更新情報をチェックする

2010年11月12日

Rails 3でタグクラウドを実装してみる

タグクラウドを実装したいと思いRails 3 で利用できるプラグインを探していたところacts-as-taggable-onというのを見つけたので実装してみました。
そのメモを残しておきます。


最初にacts-as-taggable-onを使えるようにインストールとマイグレーションを実行します。
 インストール:
 Gemfileに以下のように追加
   gem 'acts-as-taggable-on'
 インストールを実行
   bundle install
 マイグレーション:
   rails generate acts_as_taggable_on:migration
   rake db:migrate


今回はEntriesを作って、それにタグを付けられるようにします。
とりあえずscaffoldでジェネレートしておきます。
  rails g scaffold entry name:string
  rake db:migrate

Entryのヘルパーにinclude ActsAsTaggableOn::TagsHelper を追加します。
  module EntriesHelper
    include ActsAsTaggableOn::TagsHelper
  end

Entryモデルにacts_as_taggable_on :tagsを追加します。
  class Entry < ActiveRecord::Base
    acts_as_taggable_on :tags
  end
  ※:tagsの部分は他の文字列でも良いようです。また複数指定できるようです。

フォームを編集しタグを入力できるようにします。
  entries\_form.html.erbに以下のように追加します。
    <div class="field">
      <%= f.label :tag_list, 'タグ' %><br />
      <%= f.text_field :tag_list %>
    </div>

コントローラーのindexメソッドを編集します。
  entries_controller.rbのindexメソッドを以下のように書き換えます。
    def index
     if params[:tag]
       @entries = Entry.tagged_with(params[:tag])
     else
       @entries = Entry.all
     end
  end
 おそらくもっと素敵な書き方があると思うのですが、動いたので今のところはこれで良しとします。
 なお、:tagとしているのは、Entryモデルにacts_as_taggable_on の後に:tagsとして追加しているためです。

ビューを編集してタグクラウドを表示するようにします。
entries\index.html.erbに以下のように追加します。
  <h3>タグクラウド:</h3>
  <% @tags = Entry.tag_counts %>
    <% tag_cloud(@tags, %w(css1 css2 css3 css4)) do |tag, css_class| %>
    <%= link_to tag.name, {:action=>'index', :tag=>tag.name}, :class => css_class%>
  <% end %>

最後にCSSにタグクラウドで文字サイズが変更されるように定義します。
  .css1 { font-size: 1.0em; }
  .css2 { font-size: 1.2em; }
  .css3 { font-size: 1.4em; }
  .css4 { font-size: 1.6em; }

以上で殺風景ですけど、基本的なタグクラウドが実装できました。
タグ:Rails
posted by まーつん at 22:25| Comment(0) | TrackBack(0) | Ruby on Rails | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。