PaperClipはとってもシンプルなActiveRecordで添付ファイルを管理するプラグインです。

http://github.com/thoughtbot/paperclip/tree/master

便利すぎて鼻血がでそうなプラグインです

使い方のおさらい

カラムを追加して

  class AddAvatarColumnsToUser < ActiveRecord::Migration
    def self.up
      add_column :users, :avatar_file_name,    :string
      add_column :users, :avatar_content_type, :string
      add_column :users, :avatar_file_size,    :integer
      add_column :users, :avatar_updated_at,   :datetime
    end

    def self.down
      remove_column :users, :avatar_file_name
      remove_column :users, :avatar_content_type
      remove_column :users, :avatar_file_size
      remove_column :users, :avatar_updated_at
    end
  end

モデルクラスで定義

class User < ActiveRecord::Base
    has_attached_file :avatar
end

とするだけですね。 詳細はRDocをみてください

Amazon S3を使う

PaperClipはストレージにS3を使うためのオプションがあります

has_attached_file :avatar,
    :storage => :s3,
    :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
    :path => ":attachment/:id/:style.:extension",
    :bucket => 'mybucket'

config/s3.ymlには

access_key_id: 456...
secret_access_key: 456...

こんな感じのアクセスキーとシークレットキーを置いておきます

productionでだけS3を使いたい

開発中はローカルで完結したい場合は

  has_attached_file :avatar, Proc.new {
    if RAILS_ENV == 'production'
      {
        :storage => :s3,
        :s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
        :path => ":attachment/:id/:style.:extension",
        :bucket => 'mybucket'
      }
    else
      {}
    end
  }.call

こんな感じでいいかな

Posted in ruby, ruby on rails at 9月 9th, 2009. No Comments.

こんにちは、久々ですね

Railsでroutes.rbは本当に便利ですよね。

map.resources :users

なんて書くだけで、RESTFulなAPIが用意されます。

  • index
  • new
  • create
  • show
  • edit
  • update
  • destroy

に対応したURLをRailsがよしなにやってくれますよね。

しかし、こんなにたくさんのアクションはいらないー。わしゃcreateとshowだけでいいんじゃーなんて時もあったりします。そんなときは

map.resources :users, :only => ['create','show']

として、必要なアクションだけ列挙しましょう。

また、:exceptなんてオプションもあって、必要ないオプションを列挙します。

このへんにかいてありました

Posted in ruby, ruby on rails at 9月 4th, 2009. No Comments.

Railsが2.3.3に上がったので、gemをアップグレードしたりパッケージをアップデートしたりしているうちに
script/autospecが動かなくなってしまった。

解決方法はここを参考にしました

ZenTestを4.0系→4.1系にバージョンアップする場合の注意点
http://d.hatena.ne.jp/TrinityT/20090630/1246334665

  • autotest-railsをインストール
sudo gem install autotest-rails
  • ZenTest-4.0.0/lib/autotest/*をZenTest-4.1.3/lib/autotest/ へコピー
# Macではこんな感じ
sudo rsync -ave /Library/Ruby/Gems/1.8/gems/ZenTest-4.0.0/lib/autotest/ /Library/Ruby/Gems/1.8/gems/ZenTest-4.1.3/lib/autotest

これでまたscript/autospecが使えるようになりました。

Posted in ruby, ruby on rails at 7月 23rd, 2009. No Comments.

DBに配列やハッシュのデータを保存したいなと思って調べました。

ActiveRecord.serializeで実に簡単に実現できるんですね。
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002229

If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on retrieval or SerializationTypeMismatch will be raised.

このメソッドでオブジェクトとして保存・取得したい属性の名前を指定すると、自動的に処理されるようになる。 YAMLでシリアライズされ、class_nameオプションが指定されると格納できるオブジェクトのクラスを制限できる。あるいはSerializationTypeMismatchの例外となる。

ポイント

  • シリアライズしたいカラムの型をtextにする
  • serializeメソッドでカラムを指定する
  • 格納できるクラスを指定可能
  • 内部的にはYAML

実例

さて、やってみます

まずマイグレーション内で、text型のdataというフィールドを用意する。
ここにシリアライズしたデータが格納されます。

class CreateItems < ActiveRecord::Migration
  def self.up
    create_table :items do |t|
      t.text :data
    end
  end
  def self.down
    drop_table :items
  end
end

そしてモデル内でシリアライズするフィールドを指定。

class Item < ActiveRecord::Base
  # シリアライズされたデータとして扱いたいフィールドを指定する
  serialize :data
end

script/consoleなどをおもむろに起動し、本当にオブジェクトが保存できるのか確認します。

# 配列を代入する
Item.create :data => [1,2,3]

item = Item.find(:all).last
p item.data #=>[1,2]
p item.data.class #=>Array

ちゃんと配列として取得できました。めでたしめでたし。

どうなってるの?

DBに格納する際にオブジェクトをYAML化しているようです。

検索したい場合

findしたい場合は、オブジェクトではなく文字列として評価されてしまうので Object#to_yamlを使うことになります。

Item.find_by_params([1,2,3]) # => これではレコードが見つからない
Item.find_by_params([1,2,3].to_yaml) # => 見つかる

使い勝手が悪い。。

格納する型を限定する

このままだとオブジェクトならなんでも格納できてしまいます。 そこで格納するクラスを指定してやります。

class Item < ActiveRecord::Base
  # 配列以外のクラスは格納しない
  serialize :data, Array
end

script/consoleで試してみます

# 配列の格納は成功
>> Item.create :data => ['bob','alice']
=> #<item id: 1, data: ["bob", "alice"]>

# ハッシュの格納は例外が発生する
>> Item.create :data => {:name => 'bob'}
ActiveRecord::SerializationTypeMismatch: data was supposed to be a Array, but was a Hash

これでかなり使い勝手が良くなりましたけど、配列の中身までは保証できないので、精神的安定のために使う程度でしょうか?

最後に

DBにシリアライズしたデータを保存しなければならない状況は無いにこした事は無いと思いますので 設計レベルで回避できる場合はそちらをおすすめします。

Posted in ruby on rails, 日記 at 5月 21st, 2009. No Comments.

factorygirl

フィクスチャはメンテナンスしづらい

書籍The Rails Wayの中には「皆フィクスチャが嫌い」という項目があります(次の項目は「フィクスチャはそれほど悪くない」ですが)。

フィクスチャが嫌われる最大の原因は「メンテナンスが難しい」という事でしょう。
中間テーブルを必要とする多対多の関連をフィクスチャにしようと思ってうんざりした経験は誰にもでもあると思います。

Fixtureのhas_manyでこんな書き方したい
http://www.func09.com/wordpress/archives/369

フィクスチャの代わりにFactoryGirlを使ってみる

Factory GirlはRailsのテストにおいてfixtureの代替となるツールです。
つまりテスト時のモデルデータを用意するための仕組みです。
Factory Girlはフィクスチャと違い、Rubyのスクリプトで直接データを定義していきます。

特徴としては

  • Rubyコードで定義(YAMLやCSVではない)
  • 関連のメンテナンスが楽
  • 定義の継承もできる
  • 同じ定義から連続的なデータを生成できる(シーケンス)

Rubyコードで実データを作る感覚でテストデータを定義するので、フィクスチャと違い中間テーブルのメンテナンスから解放されます。 Read More…

Posted in ruby, ruby on rails, 日記 at 4月 26th, 2009. No Comments.

例えばActiveRecordで新規作成したタイミングでリモートにアクセスするような処理があったとして

class Item < ActiveRecord::Base
  before_create :do_something_with_remote
  def do_something_with_remote
    open(self.url)
  end
end

この場合、テストの時はItem#do_something_with_remoteをスタブにするよね。

item = Item.new :url => 'http://www.example.com'
item.stub! :do_something_with_remote

本当はこんな感じでかけたい

Item.stub_instance_method(:do_something_with_remote)

stubはそのオブジェクトにしか使えない?インスタンスメソッドまで影響するスタブはどう書けば良い?

Fixtureの代わりにFactoryGirlを使い始めた。 これがなかなかシンプルで使い勝手が良いんだけど、関連を設定する時に上記のような作りの場合にちょっと困っている。 Factory.defineの中でインスタンスのメソッドにstubを設定できればいいんだよな。

Factory.define :item, :class => Item do |item|
  item.stub!(:do_something_with_remote)
end

明日改造できるかソースコードを見てみる。 Factory.stubはあるんだし、できないことはないよな。

今は時間がないのでスペックヘルパーで

class Item
  def do_something_remote;end
end

みたいに上書きして対処しているが・・・駄目だよな。
FactoryGirlに関してはノウハウが溜まったら書くかも。

Posted in ruby on rails at 4月 24th, 2009. No Comments.

Mitaka.rb設立総会
http://atnd.org/events/540

Akasaka.rb,Akasaka.rb,Tokyu.rbなどローカルグループが多く存在するRubyコミュニティですが
いよいよMitaka.rbが発足する模様。

OneRingToFindの榊さんが幹事だそうです。

三鷹・吉祥寺に住んでいた期間が長く、ほんとに愛している街なので、何かしら三鷹・吉祥寺に貢献できんものかと考えている現千葉県在住の私です。脊髄反射で参加申込しましたとも、ええ。

Ruby界隈の集まりに参加するのは初めてなので、ちょっとドキドキですが。参加者の皆さんよろしくお願いします!

Posted in ruby, ruby on rails, 日記 at 4月 11th, 2009. No Comments.

はじめに

先日エントリーに書いた「Rails Searchable API Doc」のような、便利なRDocを自分のプロジェクトにも適用したい。 それを可能にするためのGemパッケージ「sdoc」がRails Searchable API Docの作者から提供されています。

これはさっそく使ってみたいと思います。

インストール

githubからインストールします。
jsonとrdocの新しいバージョンを要求されますのでインストールしておきます。

sudo gem install rdoc
sudo gem install json
sudo gem install voloko-sdoc --source http://gems.github.com

これでsdocというコマンドが実行できるようになりました。
sdocはrdocにSHTMLというフォーマットを追加してラップしただけのもののようです。

ちなみにRDocの2.4からだと思うのですがデフォルトのテンプレートがDarkFishというちょっとクールなものに変わっているみたいです。あんまりRubyっぽくないデザインです。

使い方

使い方は非常に簡単です

sdoc ディレクトリ名

と実行すればdocフォルダを作成しその中にドキュメントのHTMLを作成してくれます。

Railsのプロジェクトをドキュメント化したい場合、プロジェクトフォルダ内で

sdoc . -o doc/s_app -U -x vendor -x test -x doc -x tmp -x script -x public -x log -x config

と実行すればOKです。

無視するディレクトリは-xオプションで指定します。

Rake化

単純なRakeタスクにしておいても良いでしょう。

Railsのプロジェクトのlib/taskにsdoc.rakeというファイルを生成して、以下のようにシェルを実行する記述をします。

# lib/task/sdoc.rake
namespace :doc do
  namespace :sdoc do
    desc "Generate SDoc Documentation"
    task :app do
      output = 'doc/s_app'
      ignores = %w{vendor test doc tmp script public log config}
      rm_rf output
      option_exclude = ignores.map{|i| "-x #{i}"}.join(" ")
      sh "sdoc . -o #{output} -U #{option_exclude}"
    end
  end
end

で、Rakeタスクを実行です。

rake doc:sdoc:app

で、ドキュメントをdoc/s_appに生成します。

rdoc-documentation

どうですか?サーチャブルなRDocが自分のプロジェクトにも適用されました!
これはがんばってコメントを書こうというモチベーションにも繋がります!素晴らしい!

バグ

素晴らしいと喜んでいたのも束の間、バグを見つけました。(2009-04-03現在)

ドキュメントのテンプレートの中に「%charset%」という置き換えされない文字列がありました。
そうです文字コード指定ができないので、日本語が化け化けです。

大したバグじゃないのでGithubでフォークして直してみました。
本体にプッシュ要求する方法を知らないのでどうしたらいいのだろうか・・?英語も書けないしなー。だれかテーチミー。

直したdiff http://github.com/func09/sdoc/commit/820e29a25efc7957d25dda4d128cae9f2e20844d

参考ページ

さいごに

当初はsdocを使いたいというよりも、RDocのテンプレートの書き方を知りたいと思っていろいろ探したんですが、いまいち良くわからなかった。テンプレートとフォーマットの違いって何だろう?

調べながらRDocのソースを読んでいると、やっぱすごい人のソースはすごいなぁと。こういうメジャーなライブラリのひとつやふたつ隅から隅まで読んでみる、なんてことしてみたいが・・。

Posted in ruby, ruby on rails, 日記 at 4月 3rd, 2009. No Comments.

はじめに

The Rails Wayを読了しました。 Railsの本は出版されたら大抵買って読むようにしているのですがその中でもかなり良著だったと思います。 これから読む人はRailsアジャイルによるWebアプリケーション入門の後くらいに読むと良いですね。

さて、Rails Wayの素敵な点はテストに結構なページを割いているという点です。 Rails標準のテストとRspecによるテストにそれぞれ章だててあり、ページ数にすると60Pを超えます。 本当はRspecだけで一冊書いてほしいくらいなんですが、それでも今日本語で読める本としては一番多いと思います。

Rspecの結果表示

rake specでもscript/autospecでもいいんですが、何も考えずに使っていると下の画像のようになります。

e9d34049a45293d49131e67dcf884f90

ま、これでもいいっちゃいいんですが フォーマットを買えてリスト表示(specdoc)にしたいなぁと思いました。

spec -cfs spec/hoge_spec.rb

こうオプションを渡した時みたいにね。

spec/spec.opts

specフォルダの中にspec.optsというファイルがあります。こいつの内容を見ると

--colour
--format progress
--loadby mtime
--reverse

おー、見覚えのある文字列が。。specコマンドに渡せるオプションをここに書けばフォーマットも変えることができそう。

--colour
--format specdoc
--loadby mtime
--reverse

こう書き換えたら・・

9271e70b85e8ca0f662ca3ee02a50f17

こうなりました。

こっちの方がいいっすね。

Posted in ruby on rails, 日記 at 3月 30th, 2009. No Comments.

どんなツール(プログラミング言語、フレームワーク)でも、リファレンスを上手く引けなければ、ツールを使いこなすことはできない。

日々Railsによる開発をしている皆様方におかれましては、ブラウザのアドレスバーに「api」と入力した瞬間「api.rubyonrails.org」が補完されていることと思います。

こんな風に

apiをアドレスバーに入れると

http://api.rubyonrails.org/

は、Ruby on RailsのAPIを網羅したRails開発において欠かす事のできないページですね。
内容も丁寧でわかりやすいんですが、APIが探しにくいという致命的な欠点がありました。

今まではブラウザのページ内検索を駆使してがんばってきたのですが、そんな努力とも今日でお別れです。

Rails Searchable API Doc
http://railsapi.com/
http://railsapi.com/doc/v2.3.2/

見慣れたAPIページの使いにくいフレームの代わりに、スマートな検索を実現するサイドバーが提供されています。

Rails Searchable API Doc

  • クラス、モジュール別の階層表示
  • スマート検索
  • 過去に検索した項目を表示(Safariのみ)
  • ファイル検索
  • ネームスペースによる絞り込み
  • キーボードナビゲーション

といった機能が提供されており、非常に快適にRailsの膨大なAPIの中からお目当てのメソッドを検索できますよ!

超おすすめ。

Posted in ruby, ruby on rails, Webサービス, 日記 at 3月 27th, 2009. No Comments.