2011-02-01 [長年日記]
_ Chatter.com試してみた
クラウド的な社内コミュニケーションを預かる Sysadmin 的な意味で試してみた。
パッと見
- facebook が簡素になったというか twitter が facebook っぽくなったような感じ
- メールアドレスのドメインで参加制限が自動的に掛かる非公開 friendfeed group みたいな感じ
- 全社グループがデフォルトでできて、それ以外に部署やチームなどの group を複数作成できる
- 基本は小さなメッセージのやりとりで、ファイルの添付もできる
- Web UI のほかに AIR アプリとモバイルアプリがある
- ガラケーはたぶん非対応
実は friendfeed で非公開 group を運用してたんだけど、絶対そっちの方が面倒くさい。chatter.com で使える同一ドメイン同士なら chatter.com の方が楽。逆にドメインを越えたチームを作りたければ Google や Zoho など別なものが必要。
よく分かっていないところや不満
- モデレータ権限は与えられるが管理権限は与えられないのだろうか。というか管理できる内容が今ひとつ分かってない。
- 今自分がどの timeline を見ているのか分かりにくい。group の timeline を見ているのか followee の timeline を見ているのか。
- 同時に、どこに post しようとしているのか分かりにくい。group に post にはたぶん慣れが必要。
- アプリはともかく Web UI すごく重い
- AIR アプリは PPC Mac じゃ動かなかった><
まとめ
friendfeed は facebook に飼い殺されてしまったような感じになってしまっているけど、インターフェイスは friendfeed の方がずっと分かりやすい。でも機能的には Chatter.com の方が断然企業ニーズに合ってると思う。
cf. 社内ナレッジの「逆引き辞典」をChatterで実現--日テレ アックスオンのChatter導入奮闘記 - 事例 - ZDNet Japan
[2011-02-15 追記]
chatter.com の検索はもしかしてユーザー名、グループ名、テキストファイルの内容、に制限されているかも。普通のtweet(?)が引っ掛かってこないような気がする。
2011-02-02 [長年日記]
_ easy_fabricator とか作ってみた。
あるいは。
Ruby で動的に class を定義したかった。
twitter 上で何人かにそんなんできるよって言われたんだけど、どうにも伝わらなかった部分。
class を生成したいんじゃなくて、class 構文を使わずに class を定義したい。
なんでかというと
Fabricator は Model 相当の class の名前を Symbol で与えて使うから
ゴニョゴニョしてできたものはこれ。
具体的に困ったこと、解決したことは何か
- Object.const_set( NAME, classobj ) で好きなタイミングで class 定義できる
- Klass = な書き方はメソッドの中では不可能
- fabrication の DSL はちょっと注意が必要
例えば open や catch とかって attribute を用意してしまうと困る。
Fabricator( :model ) do
open { ... }
catch { ... }
end
って書き方になるんだけど、これは通常のメソッド呼び出しになるので定義できない。
回避方法あるのかなぁ。あったら嬉しいんだけど。ダミーデータ用のツールのために元の名前に制限があったらちょっと本末転倒だよね。
2011-02-05 [長年日記]
_ kanazawa.js v1.0 に参加した
kanazawa.js v1.0 〜JavaScriptコトハジメ〜(2011年2月5日開催)
個人的にはコトハジメではないので満席の一つを消費してしまったことにちょっとした後ろめたさを感じつつ参加してきた。
当日はかぶりつきの席で tsuda りながら 2つ3つ内職を片付けていた。内容は他の人のブログや本家記事に譲るとして、ざっくりとした感想を。
セミナー
内容が JavaScript と Shibuya.js の歴史、ネタてんこ盛りの JS だけでも結構いろいろできるよ話、網羅的な jQuery 入門、DOM を中心にしたインパクトもあり実践的な話など、コトハジメの人が消化しきるにはかなりのボリュームになった感があるけど、これだけの内容がこの短時間で2000円で手に入るとしたらお得なイベントと言ってよかったと思う。
受付を始めとした進行の体制もしっかりしてたし、会場が最初暑すぎたことを除けばほぼパーフェクトと言っていいと思う。今できる範囲のコトハジメイベントとしては最高レベルじゃないかな。
懇親会
一応あちこち回ったんだけど、回収できた名刺が17枚。何人も知ってる人がいたのもあるけど、半分も行ってない。まだまだだなぁ。
参加する気なかったのに二次会に行った辺りから徐々に乱暴な感じに。申し訳ありませんでした。
今後
kanazawa.js は発起人がデザイナということもあり、今回の参加者にはデザイナも女子も多く、普段のおっさんとしか会えない勉強会とは違う雰囲気を楽しむことができた。
ただ個人的に気になるのは今後。北陸ではこうしたセミナー形式のイベントの受けは悪くない。しかし実際に自分で手を動かし、発表する側に回る人はなかなか出てこない。これはいつもどの勉強会に参加しても感じるところ。喋る人がすぐに固定化されてしまうのだ。
kanazawa.js は発表ではなく自習を基本にするという、あまり今までにないスタイルなので予測がつきにくいが、kanazawa.js の真価が問われるのは次回
以降に掛かっていると思う。というわけで今回のイベントで盛り上がって
JS 書くぜ書くぜ書くぜ!
ってなった人はぜひ実際に書きにきてほしい。
JS 書いたなら使っていいッ!
cf.
kanazawa.js v1.0 〜JavaScriptコトハジメ〜 開催しました。 | MOL
AirMac Extreme で無線飛ばしたってことはしいのき迎賓館のガーデンルームに有線は来てるのか。意外。
kanazawa.js v1.0.1 勉強会 - (財)石川県産業創出支援機構(ISICO)
こういうところにも情報発信していたようです。知らなかった。
2011-02-06 [長年日記]
_ bluepillを知る
最近 Ruby 関係のことを知るのに都合のいい情報源は
- E和の人のtweet
- Stack Overflow
であることが多い。いやもちろんるびまも重宝していますが。
というわけで bluepill もそんな情報源から知った一つ。何かと思って調べたら Matrix 的なものではなく、
God が memory leak するから書いたものらしい。それ以外に気になるのは syslog に落とせるくらいか。そんなに大きな違いはないというかむしろものすごく God に似ている。
とりあえず今 God で困ってないんだけど、押さえておこう。
[2011-02-15 追記]
Ruby 1.9.2 の問題という話もあるみたい。
2011-02-16 [長年日記]
_ Forgeryの独自辞書でFabricateする
それぞれの言葉の意味を知らないとさっぱり想像もつかないタイトルになってしまった。
えーと Ruby でダミーデータを生成するためのツールを自分で拡張する話です。
Forgeryは独自辞書を持てる
どうもそうっぽいなぁというのはドキュメントを見てると想像がつくんだけど、具体的にどうしたらいいかはちょっとすぐには分からなかった。でもこれ見てだいたい分かった。
Forgery Gem, How to create Dictonaries and Forgeries « Ruby NYC
まとめると Ruby のコード的には
- Forgery を継承したクラスを作る
- そのクラスの中で dictionaries[:dictionary] と書くと symbol で書いた名前の、独自に定義した辞書ファイルの内容を読み込むことができる
ということらしい。
Rails 環境下のパスが載っているが、これはちょっと違うみたい。
独自Forgery用のディレクトリ
Rails 3.0.4 + Forgery 0.3.7 環境で
rails g forgery
とすると所定のディレクトリがダダッとできる。それが以下。
lib/
└── forgery/
├── dictionaries/
├── extensions/
├── forgeries/
└── formats/
これを forgery のコード内では
require 'forgery/forgery_railtie' if Forgery.rails? && Rails::VERSION::STRING >= "3.0.0"
から
Forgery.load_from! "#{Rails.root}/lib/forgery"
こう繋いでいるので、
Forgery.load_from!( DIRECTORY )
としたら
DIRECTORY/ ├── dictionaries/ ├── extensions/ ├── forgeries/ └── formats/
こういうディレクトリの中から forgery クラスや辞書を探すという動きをする。
独自Forgeryクラスの定義方法
上の記事のサンプルでは
class MyForgery < Forgery
...
def self.method
...
end
...
end
のような形になってるんだけど、これは
class Forgery::My < Forgery
...
def self.method
...
end
...
end
にしておくと、Alternate syntax で
Forgery(:my)
のように呼び出すことができる。
メソッドはクラスメソッドにしておくとスムーズに呼び出し可能。
独自辞書の定義と利用
例えば以下のようにファイルを置いた場合には
DIRECTORY/
└── dictionaries/
├ foo
└ bar
以下のように呼び出すことができる。
class Forgery::My < Forgery
...
def self.method
...
dictionaries[:foo]
dictionaries[:bar]
...
end
...
end
辞書ファイルは
- 拡張子なし
- 1行1項目
で書く。
dictionaries の戻り値は Array なので Array のメソッドがいろいろ使える。
Fabricatorからどう使うか
同じく Rails 環境のまま話を進めると
rails g fabrication:model NAME
が使えるので、指示通りに作ると
spec/fabricators/NAME_fabricator.rb
ファイルができる。まだ試してないのでよく分からないけど、ここで Fabricator を定義しておいて spec の中で Fabricate して使えということらしい。しかしここで個人的には疑問があって、
- fabricator を fixture_replacement にしてしまうと spec 走るたびにデータが変わっちゃって、テスト書きにくくない?
- 正しく意図通りに fabricate できてるかどうかすぐにチェックできなくてもどかしくない?
の二点がすごく気になっている。
easy_fabricatorを使う
上の疑問については自分で解決できなかったので、先日作った easy_fabricator を使うようにすると少しマシかなと思っている。
require 'forgery' Forgery.load_from!( DIRECTORY )
を書いてやれば独自定義の辞書を使った独自 Forgery クラスが利用できるので、これを書き足したうえで
script/easy_fabricator
として置いてみた。うむ、これは便利だな。辞書を定義している途中経過とかで確認しやすい。
これでできあがったものを CSV や YAML で吐いてそのまま fixture として利用してもいいんだし。というか、実は最初からそのつもりで easy_fabricator を書いたんだけど。
まとめ
なんとか独自の辞書を使ったダミーデータを作れるようになった。まだ辞書が足りないので十分に活用できていないが、地味に地味によくしていく予定。
それはともかく、
動的にダミーデータを生成する場合のテストってどう書くのがいいのか、誰か教えてください。
もう一つ。
独自クラス独自辞書を追加するためのgemができたら便利だよね。
2011-02-17 [長年日記]
_ JavaScriptをノンプログラマに教えるMEMO
まだまったくもってメモレベル。方針とか気づいたこととかごちゃ混ぜ。
jQuery前提
とりあえず jQuery 前提で。宗教戦争には興味なし。小さく十分なことができ情報が豊富、と三拍子揃ったライブラリはそれほどない。
アプリケーションを書きたいプログラマは自分の好きなものを選べばよい。
JavaScriptの記述位置
JavaScript(以下、JSと略記)
- 外部ファイルに書く
- 基本的には HTML の </body> の上で読む
- こうやって書く
jQuery( function($) {
...
});
1, 2 は比較的簡単に説明できるが 3 は面倒なので端折る。突っ込んでくる人がいてもその人の理解のレベルを見て判断する。
JSの記述位置と実行タイミング
理解する気と力のある人には説明する。
- 基本的に JS は書いた位置でそのまま実行される
- function で囲めば呼び出されたタイミングで実行される
- jQuery( function($) {} ); で囲むと HTML が組み上がってから実行され、かつ他のライブラリを利用するパーツと組み合わせても安全
- HTML の上の方に書くと HTML の読み込み前に JS の解釈が走って「見た目」の出来上がりが遅くなるので下に書く
JS の実行が遅れることによる「見た目の変化」が気になる場合は上に置いて一工夫することになるが、それは応用編にしておく。
Firebugとconsole.log
alert() は捨てる。
- Firebug をすでに使っていることが前提
- コンソールってあるよ
- ここで実行もできるよ
- JS の中で console と書くとこの「コンソール」を意味するよ。そこに log() でメッセージを書けるよ。
最初しつこいくらい console.log() を書いて確認してもらう。コンソール直叩きはそのあとで。ある程度コードが長く(と言っても10行くらいでいいんだけど)なってきた際に console.log が自然に出てこないと困る。
セレクタセレクタセレクタ
セレクタの知識不足は致命的。セレクタをセレクタとして認識できないとセレクタをクォートで囲んで与えるという説明も通じない。
「何を」「どうする」の「何を」がないと始まらない。
CSS 3 セレクタの知識も大事。この知識の足りないプログラマは無駄な処理を自分で作り込み始めてしまう。ここはノンプログラマ側から攻めてやるべき。「書かずに実現する」ことが「書いて実現する」ことより重要。
オブジェクト.メソッド()
メソッドの前の . を忘れたり後ろの ( ) を忘れたりする。とにかく型で覚える。
オブジェクト.メソッド()
これが分かればコードのかなりの部分の「型」が分かるはず。
文字列
ノンプログラマは地の文と文字列の区別がつかない。だからコードのパーツを捉えられるようにサポートする。これはオブジェクトの名前、これはメソッド、ここからここまでが引数。
コードのいわば「品詞」が分かるまではそれなりに時間が掛かる。短めのコードをたくさん読んで動きを理解するのが大切。
引数
- ( ) の中に何を与えるのかはメソッド次第
- メソッド( ) のリファレンスを読まないと分からない。読め。絶対。
ここら辺は比較的覚えればいい HTML や CSS とは異なる。リファレンスをざっくり理解し、いつでも引けるようにしておく、ちゃんと補完される環境を知るなどの努力が必要。
リファレンスはカタマリで読め
とりあえず
- Attributes
- CSS
- Effect
- Event
- Selectors
その後
- Manipulation
- Utilities の .each()
くらいかなぁ。
メソッド名だけで調べて完結してしまうのではなく、カタマリで「読む」と「掴めてくる」はず。
リファレンスの記法が分からなければ分かりそうな人をつかまえて聞く。聞ける人がいなくてもいっぱい読んでると結構分かってくる。
CSSとの組み合わせ
JSの中でHTMLの要素を自動で作られるとCSSが当たらないけどどうしたらいいの?
という話。公開されているスクリプトを設置してそのデザインをカスタマイズする、というのはかなりよくある話だと思う。
まずは要素の特定
- ドキュメントを読む
- 書いてないのはクソ。できるだけ採用しない。
- どのような要素が存在しているかを inspect できること
- inspect しても分からない場合は jQuery plugin なら jQuery のリファレンスの manipulation のメソッド呼び出しを探す
- そこできっと何かが起きている
リファレンス重要。
スタイルを書く
- とりあえず jQuery.css() で書いちゃう
- 何に対してスタイルを当てればよいのかを知るにはこれが早い
- できるだけ外部 CSS の important! でやってみる
- Stylish を併用するといいかも
CSS はやはり独立した CSS ファイルの中にあった方がエラーチェックもちゃんと機能するしメンテしやすい。
小さい課題からやる、何度も同じ課題をやる
- いきなり何行もコードを書かなきゃいけないことに興味を持つとハードルが高い
短いといってもまったく読めない状態での数行は読める人の100行くらいに相当するかもしれない。
- 何度も同じ課題をやる
さすがにまったく同じではない方がよい。自分でちょっとだけ違うバージョンを想定してそれをいくつも練習する。そうやって記法やリズムを自分の身体に染み込ませる。他の人は知らないけど自分は「書く」行為にはリズムが大切だと思っている。コードはただの字面じゃない。
コメント
基本は CSS と同じにしておくといいかも。
/* ... */
ただ
//
以降行末までという形もあるので、見てもビックリしない。
参考
- Eventbug - 文殊堂
- jQueryを使い始めたときに感じる13の疑問 | tech.kayac.com - KAYAC engineers' blog
- break, continue は map と grep を使って先に片付けてしまうのがいいと思う
2011-02-18 [長年日記]
_ Emacs で設定ファイルとかをなんとなく見やすくする
Twtterより。
rubikitch 11/02/18 9:37 とりあえず (require 'generic-x) という行
を.emacsに加えとけ。/etc/hostsやらhttpd.confな
んかに色がつくようになるからさっ!せっかく機能
があるのになんで標準で有効になってないの?もっ
たいない。
wtnabe 11/02/18 15:56 (require 'generic-x) 21 でも動いた
確かに便利。
普段はそんなに必要ないけど *.conf なんかをいじるときに地味に便利。Emacs 21 on CentOS でも動いた。結構昔からあるのかも。
[2011-03-09 追記]
もっと詳しく書いてくれた人がいた。
clmemo@aka: Emacs で設定ファイル (/etc/hosts, /etc/apache2.conf) の色付けをする
2011-02-19 [長年日記]
_ 今さらRails3メモ - その1 : DB操作、Model確認周りを中心に -
前回をその0とします。正直、盛り込みすぎました。
railsコマンド
- rails コマンドはものすごくよく使うので alias r=rails するらしい
- rails console が便利
特に Model の動作を確認するのに rails console が便利。要するに rails 環境が丸ごと載った irb だと思う。上の alias と合わせて
r c
で呼べるようにしておく。またこの console 上で
reload!
すると model などの変更に追随できる。
ただし、文字通り reload するだけなので新たに追加されたものは反映されない。
- rails server でサーバを起こす
凝った使い方はしたことがない。普通に port 3000 で WEBRick を使ってる。
-u --debugger
オプションはのちのち便利。
development のうちは基本的にファイルの変更には自動で追随してくれるんだけど、
config/locals/ 以下のファイルが増減したときには再起動しないとダメ
なのはちょっと忘れがち。他にもそういうのあるかもしれないけど、ちょっとよく分かってない。とりあえず「あれー反映されてないな?」と思ったら再起動オススメ。
- rails generate はやたら使う
だから
r g
で呼び出す。model, helper, migration, 他のツールなどかなりのものがここから作業を開始する。
- rails dbconsole は適切な設定で sqlite コマンドや psql コマンドなどを叩いてくれる
Model からではなく生の DB の様子を確認するのに使う。こうしたツールに不慣れな人はあまり嬉しい機能じゃないかな。SQLite くらいなら GUI のツールが充実してるので development の間はそれで押すのも手かも。
最近自分は Rinari の rinari-sql を経由して使ってることが多いかも。
rvm で複数の ruby を入れている場合
あんまりこんなことやらないと思うけど、複数の ruby を入れて検証を行う場合、
- rvm use で ruby の切り替え
- bundle install
- source ~/.zshrc ( bash でもなんでも )
が必要。最後の source をやらないと alias の r から呼び出される rails コマンドがそれまで使っていた ruby で動くのでややこしくなる。
rvm wrapper を使えばもしかしたら解決する問題かもしれないけど、やったことないので分からない。
rakeタスク
とりあえず rake -T db の部分。
- create, drop, migrate, rollback は(端折って)いいよね
- db:fixtures:load で fixture ファイルを読み込める
基本的に fixtures は test 環境で利用するものでパスも
test/fixtures/
以下になっている(デフォルト)。これを development 環境で読み込むのに
rake db:fixtures:load
が使える。ただし、対象のテーブルにそれまで入っていたデータはクリアされる。
- db:setup が便利
基本は db:migrate でいいんだけど、何回もやり直してるうちに一度きれいにして初期データを入れ直したいと思うことがある。そんなとき setup が便利。
datebase.rake の中で
task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
と定義されているので、rake db:setup だけで、create して
db/schema.rb db/seeds.rb
を実行してくれる。
てなことを2ヶ月前に Twitter で教えてもらっていた。
Twitter / @ゆーけー/赤松 祐希: @wtnabe rake db:setup でdb: ...
db/seeds.rb
seeds.rb は Model 作って自分で save しろということらしい。少なくとも rails new したばかりの db/seeds.rb には何も書かれていない。そこでこんなものを作ってみた。
結構便利。
cf.
Twitter / @Dai Akatsuka: @wtnabe Model.create(:id = ...
fixtureのパスはデフォルトの方に合わせた方がいいかも?
- 基本は test/fixtures/ 以下
- rspec の基本は spec/fixtures/ 以下
- rspec の設定は spec_helper.rb 内で変更可能
Rails 全体の設定をする場所はたぶんなくて、RAILS_ENV と FIXTURES_PATH などの環境変数経由で設定する感じっぽい。Rails の環境設定の外で指定するのはちょっと再現性に難があるので、rspec の方で
config.fixture_path = "#{::Rails.root}/test/fixtures"
して設定を変えておいた方が楽な気がする。例えば前述の
rake db:fixtures:load
は
test/fixtures/
以下を見にいく。
ところで fixture は Model の制約を無視して DB に直接データを INSERT INTO してるみたい。ということは Model の制約を無視した(DBMS の制約にだけ従う)データを突っ込むことができる。ちょっと注意が必要かも。
2011-02-20 [長年日記]
_ DBMSのexport
DBMS の seed data は手で作ってもいいけど DB から出力して生成してもよい。特に Typus などの管理画面用のツールを使っている場合、とりあえず手で入力してどんなもんか見て、それを export するようにするとお手軽だし、他の人にデータ作りを手伝ってもらいやすくなると思う。
まぁとにかくそんなこんなで DBMS の export について調べてみた。
Typus
Typus の csv export は gem v 3.0.4 以降で正しく機能する。ただし、
Typusのcsv downloadがセミコロン区切りな件 - あーありがち(2011-01-18)
に書いた通り。Comma Separated じゃない。
DBMS
Typus を採用しているのを前提として。
Typus の export 機能は大事だが、それより大事なのは開発者のデータの取り回し。Typus がうまく動かない場合は他の機能で実現する必要がある。
Rails の helper を書いて export を作ることはもちろん可能だしそれほど難しくないが、Typus の利用を前提にすると管理画面にこうした細かい機能追加を行うのはややこしいしゼロから書きたくない。
ということで次は SQL レベルの方法。(そもそも頻繁に発生しない前提。)
SQL COPY
PostgreSQL で作られたものを SQLite が porting している。つまりこの2つでは COPY コマンドが使える。
MySQL は INTO
MySQL は SELECT の INTO でファイルに吐き出したりできるみたい。
MySQL :: MySQL 5.5 Reference Manual :: 12.2.9 SELECT Syntax
なるほどな。select 一発でできてしまうとは。
SQLite でも .mode csv にすればよいし、PostgreSQL でも
-A
--no-align
Switches to unaligned output mode. (The default output mode is
otherwise aligned.)
-F separator
--field-separator separator
Use separator as the field separator for unaligned output. This
is equivalent to \pset fieldsep or \f.
-o filename
--output filename
Put all query output into file filename. This is equivalent to
the command \o.
-t
--tuples-only
Turn off printing of column names and result row count footers,
etc. This is equivalent to the \t command.
の組み合わせで実現できるかな。でも使うオプションが多いな。
2011-02-21 [長年日記]
_ 今さらRails3メモ - その2 : C, V を中心に -
とりあえず scaffold する
最初は様子がよく分からないので
r g scaffold
しちゃう。
scaffold は一躍 Rails を有名にしたものなんだけど、これは何より様子を掴むのに向いている。例えば
r g scaffold example name:text
とすると
- カラムを1つ ( name ) 持つテーブル1つ ( example ) に対応するモロモロ
を作ることができる。
実際に実行するとファイルでこれだけのものができる*1。(routes はファイルができたんじゃなくて routes.rb を書き換えたよの意味。)
invoke active_record
create db/migrate/#{SERIAL}_create_examples.rb
create app/models/example.rb
invoke rspec
create spec/models/example_spec.rb
route resources :examples
invoke scaffold_controller
create app/controllers/examples_controller.rb
invoke erb
create app/views/examples
create app/views/examples/index.html.erb
create app/views/examples/edit.html.erb
create app/views/examples/show.html.erb
create app/views/examples/new.html.erb
create app/views/examples/_form.html.erb
invoke rspec
create spec/controllers/examples_controller_spec.rb
create spec/views/examples/edit.html.erb_spec.rb
create spec/views/examples/index.html.erb_spec.rb
create spec/views/examples/new.html.erb_spec.rb
create spec/views/examples/show.html.erb_spec.rb
invoke helper
create spec/helpers/examples_helper_spec.rb
create spec/routing/examples_routing_spec.rb
invoke rspec
create spec/requests/examples_spec.rb
invoke helper
create app/helpers/examples_helper.rb
invoke rspec
invoke stylesheets
create public/stylesheets/scaffold.css
上から
- db の migration
- model
- model の spec
- routing ( 一通り CRUD できるように resources になっている )
- controller
- controller の各メソッドに対応する view
- controller の spec
- view の spec
- helper の spec
- routing の spec
- requst の spec
- helper
- stylesheet
となっている。このまま
rake db:migrate r s
すると
http://localhost:3000/examples
にアクセスして実際に使える。
Controller
layout
layout "NAME"
layout ファイルを指定できる。何も指定しなければ
app/views/layouts/application.html.erb
が選択される。
※ jpmobile が有効で mobile な user agent だったら
app/views/layouts/application_mobile.html.erb
などになる。
さっき scaffold したコードを読む
Controller には index, show, new, edit, create, update, destroy のメソッドがある。それぞれ
| index | 一覧表示 |
| show | 個別表示 |
| new | 新規追加form表示 |
| edit | 既存レコードの編集form表示 |
| create | 新規追加送信先 |
| update | 既存レコードの編集結果送信先 |
| destroy | 既存レコードの削除 |
となっている。やってることは
- Model インスタンスを作る(.all(), .find(), .new())
- 必要な処理を加えて
- 結果を返す(render(), redirect_to(), head( :ok ))
以上。
Skinny Controller !
respond_to と format.xml の部分はとりあえず気にしなくていいと思う。たぶん。
View
Controller を読むと分かるけど View ってオブジェクトを明示的に作ることはない。
※ erb 以外のテンプレートは使ったことがないので知らない。
基本的なテンプレートの配置
app/controllers/#{controller}_controller.rb
app/views/#{controller}/#{action}.html.erb
controller のメソッド名に対応した view が勝手に呼ばれる。
見ると分かるけど先ほどの scaffold で指定した field ( name ) がちゃんと index, show, _form にハマっている。
ここでもう一度 Controller と見比べると
- params[:example]
- @example
- @examples
- example.name
などの意味するところが見えてくると思う。
partial の扱い
(主に V や Helper で)
render 'NAME'[, { 渡すオブジェクトのマップ }]
と指定するとこれを呼んだ View と同じディレクトリの
File.dirname( __FILE__ ) + "/_#{NAME}.html.FORMAT"
を探しにいく。例えば上で scaffold した例だと
app/views/examples/edit.html.erb app/views/examples/new.html.erb
に
<%= render 'form' %>
と書かれている。実際に呼び出されるのは同じディレクトリにある
app/views/examples/_form.html.erb
になる。
※ オブジェクトのマップについては後述。partial の呼び出しは Rails 3 で簡略化されたので 2 以前の知識のある人、2 以前を対象にした本を参考にしている人は注意。
partial を別なディレクトリに置く
partialの名前に / が入ると app/views/ 以下のどこかのパスのpartialを探しにいく。
View から見えるもの
View から Controller の持っているものは基本的にすべて見える。request, params, cookies, response, session, headers など。Controller で Model のインスタンスをインスタンス変数に持っているなら、V からもそれが見える。
だから index.html.erb で @examples.each と書いてすべてのレコードの一覧を表示することができるし、_form.html.erb でいきなり @example を参照して form を組み立てることができる。
というか `controller' で Controller そのものにもアクセスできる。つまり全部見える。テンプレートで
<%= debug( controller ) %>
として見れば分かる。
partial に渡るオブジェクトと partial の動き
partial の書き方はいろいろあるので、本当に細かいところは
Ruby on Rails Guides: Layouts and Rendering in Rails
に譲るとして、とりあえず
- インスタンス変数は何もせずにアクセスできる
- ローカル変数へのマップは :locals で明示する
- :collection を使うとループの処理書かなくてもいい具合に動く
- :action で他の action 呼び出して結果を返せる
くらいは分かっておくとよい。
HTML は helper で書くより partial の方が楽かも?
ActionView::Helpers::TagHelper
に
- content_tag
- tag
という便利メソッドがあって HTML の組み立てもラクチンにできそうだけど、デフォルトでエスケープされるし
<%= %>
は Rails 3 以降デフォルトでエスケープされるので注意が必要。とは言え動的に何か組み立てようと思ったら Helper に書いた方が見通しはよくなるので、
<%= raw helper_method %>
みたいな形に落ち着くのかな。でもこの代わりにも partial が使えるような。
<%= yield :NAME %> <%= render 'name' %>
とやって partial の方で
<% content_for :NAME do ... end %>
とか。
jpmobile が有効な場合、partial に対してもテンプレートの切り替えが有効なので、Controller や Helper で分岐を書く必要がなくなって嬉しい気がする。
form
この辺を見る。
- ri ActionView::Base
- ri ActionView::Helpers
- ri ActionView::Helpers::FormBuilder
- ri ActionView::Helpers::FormHelper
- ri ActionView::Helpers::FormOptionsHelper
- ri ActionView::Helpers::FormTagHelper
form_for が form_builder を作るメソッド。
form_for( @model ) do |f| f は FormBuilder が渡ってきている end
Model.columns を使うと column 情報は取れるので、手動で作る分にも雑な form ならすぐに作れそう。
二つの Model にまたがる場合はどうするんだろう? 宿題。
*1 Test::Unit ではなく RSpec を使う設定になっているものとする。
2011-02-22 [長年日記]
_ 今さらRails3メモ - その3: デバッグというか差し込み口と中身の確認 -
どこで何が確認できるか分かってないと結構つらいので。
差し込み口
- C の action 前後の filter ( before_filter, after_filter, around_filter )
- M の validation および create/save/destroy 前後の callback ( create, update, destroy は around もある )
- さらに M の after_initialize, after_find などにも
ここに処理を挟み込むことで C や M のロジックを複雑にしないでデバッグのためにアレコレ仕込んで確認することができる。
cf.
- Ruby on Rails Guides: Action Controller Overview
- Module: ActiveRecord::Callbacks
- Ruby on Rails Guides: Active Record Validations and Callbacks
Controller
- verify
- filter ( before, after, around )
- after は action の実行後、つまり全体では
before_filter def action; end after_filter
となっており、before_filter が走る段階で routing などは終わっている。
vefiry は文字通り vefiry しかできないので、処理を挟む余地はない。ただし model の validate をまたずに弾き返すことができるのでたぶん速い。(特殊な before_filter らしい。)
around_filter は before と after および実際のアクションの間に実行される。
- before_filter
- around_filter1
- around_filter2
- def action; end
- around_filter2
- around_filter1
- after_filter
の状態になる。
Model
結構たくさんある。順番に
- before_validation
- before_validation_on_#{CRUD}
validate
- after_validation
- after_validation_on_#{CRUD}
- before_save
- before_create
create ( だけじゃない )
- after_create
- after_save
action が走らないと Model Object は生成されないので、validate の実行タイミングは action の後というか action の中。
確認方法
- rails console で主に model の method の確認
- rails server を立ち上げた terminal で次々に起こることを目視する
- p でそこに情報を吐き出す。(これはログには落ちない)
- とても伝統的。rails server を実行している console に表示される。
- V なら debug を使う
- logger の設定を default から変更して logger インスタンスを起こす。この logger に必要な情報を吐き出す。
- debugger を起動する
1 の rails console はすごく好きなんだけど web server が動いているわけではないので request を扱うことはできない。form の作り方間違えて validation のタイミングでちゃんと値が渡ってきてないんじゃないかしらと思ったら
class Controller
before_filter do
debugger
end
end
とか
class Model
before_validation do
debugger
end
end
しておくと自由に確認できる。単に目視できればいいだけなら p でもいいけど、development のログは結構詳細に出るので簡単に流れていってしまう。多少面倒でも logger か debugger を使うとよい感じ。
4 の debug は Typus の中だとあまり機能しないような気がするので、V ならいつでも debug できるとは思わない方がいいみたい。
5 の logger の設定は思っていたより面倒だった。
6 の debugger は強力なんだけど、いちいち break してしまうのが面倒とも言える。
continue
すれば復帰できるとは言え。
logger の設定と使い方
こんな感じ。
config.logger = Logger.new( File.join( Rails.root,
'log',
"#{Rails.env}.log" ) )
config.log_level = Logger::DEBUG
を config/environments/development.rb に追加した。使う時は
logger.debug( object.to_s )
みたいな感じで。
log_level を上げればいいだけかと思ってたんだけど、なんかどうもできないっぽい。
debugger の設定と使い方
Gemfile に ruby-debug(19)? を追加
group :development do gem 'ruby-debug' if RUBY_VERSION < '1.9' gem 'ruby-debug19' if RUBY_VERSION >= '1.9' end
で、
- rails server -u ( --debugger ) でサーバを起動
- 好きな場所に debugger と書いて止める
cf.
Ruby on Rails Guides: Debugging Rails Applications
request parameters を確認する
request parameter は rails console では確認できないので、今回紹介した console 以外の方法が生きる。
- request parameter を確認するなら C の before_filter で params を見る*1
- request 全体は request メソッド
- params は request.parameters, request.headers.parameters の alias
- jpmobile 環境では request.parameters が変更されていて、オリジナルは request.parameters_without_jpmobile
- request.parameters は Http::Parameters オブジェクト
- ヘッダは request.headers
※ 脱線だが request に適用できる filter は request.methods.filter に出てくる parameter_filter, env_filter, parameter_filter_for 辺りか?
*1 こうすると無駄な処理が動かない
2011-02-23 [長年日記]
_ 今さらRails3メモ - その4: Modelのちょっと変わった基礎 -
Model は奥が深く、また Rails は Fat Model にしろ、の哲学なので長くなりそうということで小出しにする。
ActiveModelをincludeすればなんでもModelに
Rails 2 以前は ActiveRecord と密結合していたけれど、Rails 3 以降で多くの機能が ActiveModel に切り離された。ActiveRecord を使うアプリの場合はあまり関係ないけど、ActiveRecord から切り離されたということは
DBMS 関係なく Model の機能を利用できる
ことを意味する。
Model のクラスメソッドとインスタンス
Model のクラスメソッドには table_name, human_name などがあるが、Model.new したオブジェクトには存在しない。
ましてや Model.all, Model.find の検索結果に至っては Array なので .table_name, .human_name などのメソッドは存在しない。(しばらく悩んでしまった。アホすぎる。)
ということで Model の定義情報はクラスに聞け。
ただし
当たり前だけど ActiveRecord ベースでない Model には table_name などは存在しない。最終的には connection を張って取得してるらしい。
カラム定義は Model.columns に
Model.columns に必要な情報が入っている。inspect のコードを参考にすると
Model.columns.map { |c|
"#{c.name}, #{c.type}"
}
なんてことをするととりあえず欲しい情報は取れると思う。form field の自動セットとかたぶんできる。
Validation
- validates がなくて値が不正などの DBMS レベルのエラーの場合はアプリケーションの例外画面がいきなり表示される
- validates で引っ掛かったら Flash*1 でエラーメッセージを出せる
Rails 3 以降は validator は ActiveModel に属すので、それっぽいプロパティと validator を用意すれば DBMS は無関係に Form を作ったりすることもできる。
validates_* なヘルパーはクラスメソッド
これ分かってなくてハマった(情けない)んだけど、validate 関係のメソッドはクラスメソッドなのでそこからインスタンスメソッドは利用できない。要するに
こういうこと。
validatorの目視チェックを破壊的メソッドで
Ruby on Rails Guides: Active Record Validations and Callbacks
validator がちゃんと動いているかどうかは
The bang versions (e.g. save!) raise an exception if the record is invalid. The non-bang versions don’t: save and update_attributes return false, create and update just return the objects.
ということで ! のついている破壊的メソッドでデータを保存しようとすれば例外が上がって目視しやすい。
- create!
- save!
- update_attributes!
non-bang version(! のついていないメソッド)は false が返るだけだし、rails console で実行していると保存に失敗しても何らかの値がセットされた状態でオブジェクトが表示されるので、
瞬間的に保存に失敗したことを認識しにくい
ので、目視チェックは破壊的メソッドで、と覚えておくと便利。
参考
- Ruby on Rails Guides: Active Record Validations and Callbacks
- Module: ActiveModel::Validations::ClassMethods
- ri ActiveModel::Validations::ClassMethods.validates
idはcreateできないのでseed dataを作る際に注意が必要
Model.create( {} )
の際には id を与えることができない。自動で振られてしまうので。ただし
m = Model.create( {} )
m[:id] = 1
m.save
とすると id を指定できる。
cf. Twitter / Dai Akatsuka: @wtnabe Model.create(:id = ...
これの何が問題かというと、id で relation を作る seed data を作っている場合に困る。
fixture の場合はこれは問題にならない。なぜなら ActiveRecord の奥底で直接 INSERT INTO を呼んでいるから。したがってデータの作り方によって
db:fixtures:load はできるけど db:seed はできない
場合がある。
find_by_sql() で複雑なSQLをそのまま書く
Arel は確かにすごいんだけど、複雑な SQL を OO のメソッドチェインだけで実現するのはやはりホネ。素直に SQL を書いた方が簡単なケースはやはり少なからずある。
- Model.find_by_sql( ) で複雑な SQL をそのまま書ける
- ちゃんと sanitize というか quote してくれる
- Model.find_by_sql( [SQL, VAL, VAL] ) で変数への値の埋め込みができる*2
この際、join を使った検索結果を console で確認しているとちょっとハマる。console ですぐに目視できる結果は Model 内に定義されている attibute だけなのだ。
しかし実際には join した table の attribute もそのままアクセスできる。これは
Model.find_by_sql().each { |e|
e[:attr]
}
や
Model.find_by_sql().first.attributes
で確認できる。ここで確認できる attribute にアクセスするロジックを自由に書ける。
2011-02-24 [長年日記]
_ 今さらRails3メモ - その5: Model Association -
まずは設計以前の話から。(というか設計は語れません。)
あと、Rails ガイド読むならこのエントリ要らない。
Ruby on Rails Guides: A Guide to Active Record Associations
基本概念
用語
DBMS 用語としては entity の relation だと思うんだけど、Rails 的には クラスベース OOP の用語をそのまま拝借して Model(クラス)の association と呼ぶらしい。
DBMSの制約はただの約束
- 外部キー制約 = リレーションシップではない
- DBMS はこの制約を無視して構わない
- リレーションシップはテーブル設計を開発者が「そう決めた」から
リレーションシップを設定するのが外部キー制約ではないことに注意してください。外部キー制約は、列の値がターゲットテーブルの既知のキーを参照するかどうかチェックすべきことを、データベースに指示するだけです。DBMS は、この制約を無視して構いません(実際に MySQL の一部のバージョンは無視します)。テーブル間リレーションシップが設定されるのは、開発者が product_id 列と order_id 列に products テーブルと orders テーブルのキー値を入力することを決めたからです。
(『RailsによるアジャイルWebアプリケーション開発』第1版 p232)
「要は外部キーでしょ」と分かった気になっていただけでに少なからずショック。
以下、とりとめもなく感想とか。Before Rails な世界の住人としては最近のアプリの DBMS の schema dump とか見ると制約が全然なくてすごくスカスカした感じがするんだけど、DBMS の制約を使うと変更に弱くなるので使わない、という方針なんだよね。逆に Model の中身は制約というか validation がズラッと並んでいて「おぉこれは」という感じになってる。つまり Model の方に注目しなきゃいけない。だから Model を利用したうえで ER 図っぽく起こしてくれる
Rails ERD – Entity-Relationship Diagrams for Rails
みたいな道具は必須だなと感じた。こういうのなかった時代はどうしてたんだろう、ほんと。素朴な ER 図作成ツールとか使っても実態と合わないわけでしょ?
key と id
- ActiveRecord のデフォルトルールでは primary key は `id' 列(自動でセットされる)
attribute 上では変更は可能。
class Model < ActiveRecord::Base set_primary_key "code" end
ってやったら attribute 上は code が primary key になる。ただし migaration の方もいじっておかないと DBMS 上では id のまま。のはず。一応確認したけど間違ってたらごめん。
- 同じく外部キー列の名前は #{table}_id
これも
class Model < ActiveRecord::Base belongs_to :foo, :foreign_key => 'foreign_key' end
のように association の option で変更できる。
基本的なAssociation
- belongs_to
- has_one
- has_many
基本的には Rails ガイドを読めば分かる。なめちゃいけない、すごく丁寧。
- Ruby on Rails Guides: A Guide to Active Record Associations
- ruby/rails/RailsGuidesをゆっくり和訳してみたよ/Active Record Associations - 株式会社ウサギィwiki
中でも belongs_to を忘れると話にならないのでとりあえずこれだけ。
class Model < ActiveRecord::Base belongs_to :table end
そして自分の所属する table の id ( primary_key ) を保持するカラムを作る migration を用意する。
class AddForeignkeyToModel < ActiveRecord::Migration
def self.up
add_column( :models, :table_id )
end
def self.down
remove_column( :models, :table_id )
end
end
こんな感じ。
この部分は自然な読みやすさを重視してるらしく、has_many だと
class Model < ActiveRecord::Base has_many :tables end
になったりする。自然かもしれないけど、決まってないと不安な気もしないではない。
オプションもいっぱいある。
Module: ActiveRecord::Associations::ClassMethods
先に挙げた foreign key の他にもいろいろ。
応用Association
- has_and_belongs_to_many
- has_many , :through =>
- has_one, :through =>
- belongs_to , :polymorphic => true
has_and_belongs_to_many
Module: ActiveRecord::Associations::ClassMethods
いわゆる 多:多, M:N と呼ばれる関連を表現する。has_and_belongs_to を相互に書くことで結合テーブルを隠蔽した多:多の association を定義できる。
※ 素朴な話をすると 多:多 っていう relation は存在しなくて、実際この association も隠蔽されているだけで結合テーブルを利用する。DBMS の基本が分かっているなら 多:多 も特別怖がる必要はない。あくまで ORM は DBMS の使い勝手をよくするもので DBMS の機能に変化はない。
具体的には
Foo < Model has_and_belongs_to_many :bars end Bar < Model has_and_belongs_to_many :foos end
と定義すると
foos_bars
という結合テーブルを使って相互に更新される。migration は以下の通り。
class FoosBars < ActiveRecord::Migration
def self.up
create_table :foos do |t|
...
end
create_table :bars do |t|
...
end
create_table :foos_bars, :id => false do |t|
t.column :foo_id, :integer, :null => false
t.column :bar_id, :integer, :null => false
end
end
def self.down
drop_table :foos
drop_table :bars
drop_table :foos_bars
end
end
primary key を持たない(should not have)結合テーブル を手動で migration して作らなければならない(you must manually generate)。
この場合、結合テーブルに該当するモデルは定義する必要がない。言い換えると結合テーブルを操作することはできない。
class Foo bars.push_with_attributes( barのレコードオブジェクト, column symbol => 値 ) end
という形で参照先のテーブルを更新する。
has_(one|many), :through =>
結合テーブルを利用した association に独自の何かが欲しい場合もある。先ほど隠蔽した 多:多 の association を表現する Model を定義し直すと以下のようになる。
class Foo < Model has_many :bar, :through => :foo_bar end class Bar < Model has_many :foo, :through => :foo_bar end FooBar < Model belongs_to :foo (, :dependent => :destroy ) belongs_to :bar (, :dependent => :destroy ) end
明示的な Model を作ると独自の処理を自然に記述しやすくなるし、明確な意味を持たせやすい。
上の例では結合テーブルのような名前になっているが、当然名前も自由に決められる。このテーブルの意味が明確になる名前に設定するとよい。
Polymorphic
Model の関係を固定せず、似た association を複数実現する機能。仮想のテーブルをここでは :polymorphable とした場合に具体的に Model 上の記述では
Foo < Model belongs_to :POLYMORPHABLE, :polymorphic => true end Bar < Model has_XXX :foo, :as => :POLYMORPHABLE end
の組み合わせで実現する。
この際、migration では
create_table :foos do |t| t.references, :POLYMORPHABLE, :polymorphic => true end
と定義する。実際にはこれは
create_table :foos do |t| t.string, :POLYMORPHABLE_type t.integer, :POLYMORPHABLE_id end
という形に展開される。大文字の POLYMORPHABLE はもちろん小文字で。
※ この部分には名詞ではなく形容詞の -able にするのがパターンとして多いみたいだけど、明確な理由は分からない。恐らく複数形への変化の影響を受けないとか :as => -able が自然に読めるとかそういうことだと思う。
特徴は
- belongs_to では物理的なテーブル名ではなく、仮想のテーブル名を指定し、:polymorphic => true を付加
- has 側では物理的なテーブル名を指定するが :as を使って仮想のテーブル名も指定する
- belongs_to 側の table のカラムには has な table 名は直接入らない
- (ここまでに登場した association では bar_id というカラムがあるはず。)
- belongs_to 側の table は has 側の Model 名を #{POLYMORPHABLE}_type に格納する
- ここで Model 名が可変になっているので association を柔軟に変更できる
よく例に挙がるのは画像を格納するテーブルを Polymorphic で紐づける方法。例えば RSS 2.0 などでは blog そのもの、entry それぞれなどに画像を指定できるし、その数も決まっていない。したがって
class Blog < Model has_one :image, :as => :imagable end class Entry < Model has_many :images, :as => :imagable belongs_to :blog end class Image < Model belongs_to :imagable, :polymorphic => true end
のように関係を記述できる。この場合、
- :imagable_type に 'Blog' か 'Entry' が入る
- :imagable_id にそれぞれの Model の id が収まる
ことで複数の Model に belongs_to することができる。若干分かりにくいがとても便利。
上の例の Entry のインスタンスで .images を呼ぶと :image テーブルから自身に紐づいているレコードを取得できる。以下のような感じ。
entry = Entry.find(params[:id]) entry.images
単一テーブル継承との組み合わせに注意
あまりこんなことはやらないかもしれないけど。
- Polymorphic で使われる Model クラス名は DBMS のテーブルに紐づくクラス名
- 単一テーブル継承の子どものクラス名を格納してしまうと検索できない
ので注意。
参考
2011-02-25 [長年日記]
_ FasterCSV::Tableでヘッダが取得できるけど空セルに注意
罠っていうかたぶん FasterCSV の理解が足りないだけなんだけど。
FasterCSV::Table なら header を取得できる
Rails の seed data を取り込む際に
FasterCSV.open( PATH, { :headers => true,
:header_converters => :symbol } ) { |csv|
...
}
みたいにするコードはよく見かけると思うんだけど、open だと header を取得することができない。
irb(main):001:0> f = FasterCSV.open( '/path/to/csv', :headers => true ) <CSV.open( '/path/to/csv', :headers => true ) => <#FasterCSV io_type:File io_path:"/path/to/csv" lineno:0 \ col_sep:"," row_sep:"\n" quote_char:"\"" headers:true> irb(main):002:0> f.headers f.headers NoMethodError: undefined method `headers' for #<FasterCSV:0x143f084> from (irb):1
リファレンスを眺めていたら FasterCSV::Table だとできるらしい。
irb(main):003:0> g = FasterCSV.table( '/path/to/csv', :headers => true ) <CSV.table( '/path/to/csv, :headers => true ) => #<FasterCSV::Table mode:col_or_row row_count:8> irb(main):004:0> g.headers g.headers => [:name, :code]
おぉ、取れた。
FasterCSV::Table のデフォルトでは空セルが 0 になる
変更方法があるのかどうか分からないけど、
FasterCSV.table( '/path/to/csv', :headers => true ) { |csv|
...
}
ってそのままやると空セルが 0 になっちゃう。:skip_blanks っていう option が default false で存在してるので true にしてみたけど変わらず。
仕方ないので中身を取得するのに普通に open で開き直すことにした。
なんか納得いかない。
2011-02-26 [長年日記]
_ RSpecのdescribe, context, itと感想
RSpec の動かし方だけは分かってたんだけど、あんまり真面目に整理したことがなかった。少しだけ真面目にドキュメント読んでみた。
基本概念
explicit subject - Subject - RSpec Core - RSpec - Relish
RSpec is a DSL for creating executable exmaples
おぉ、なるほど。
コードが動作例のように見えることが大事ってことか。テストらしく書くのではなく動作例らしく書く。そうすると実行結果のレポートもとても自然に読める。これが設計書のように読める。
基本構造
- ファイル : spec
- describe : example group
- context : alias of group
- it : example
- context : alias of group
it はどこで定義されているのかよく分からないけど
it 'behavior' do ... テストしたい振る舞い ... end
でも
it {
...
テストしたい振る舞い
...
}
でも良いらしい。it の中身が DSL の力を借りて英文そのもののであれば `behavior' は省略しちゃうという流儀もあるらしい。
でもそれって
日本語でレポートを作れる
っていうメリットがなくなるような?
context ってどう使うの?
describe の alias として context は用意されているが、こんな感じで使うのがいいんじゃないか案。
describe MyClass do
describe 'this method' do
context '条件' do # 英語だと 'in ...' とか 'when ...' とか ?
it '振る舞い' do
obj.should be_XXX
end
end
end
end
みたいな感じがE和スタンダードみたい。(間違ってたらツッコンでください!)
確かにこれが自然かも。なるほどなぁ。
Twitter / @SHIBATA Hiroshi: @wtnabe あー、そこについてはケースバイケース ...
感心したこと
RSpec って書き方自体は知ってたんだけど、あんまり意味が分かってなかった。あと、読みやすさの代わりに書きにくさがあるなーと感じていたんだけど、これは誤解だなと思った。むしろテストを分類しやすくてとても書きやすい。
これまでも xUnit 系のツールは使っていたんだけど、なんだかとても読みにくくメンテしにくいテストコードを量産していたように思う。少なくとも確認したいことの単位でメソッドを起こしたりはしていなかった。何かを意図していたわけではないけど、一つのメソッドに対するテストメソッドが 3つも 4つもあるのも変な感じがしていたし、メソッド名が長くなりがちなのもいい印象を持てなかった。
それが RSpec だと違和感なく書ける。describe を階層化できるから確認したい振る舞いの名前に重複が発生しない。つまり DRY だ。
もう一つ、diff の出力が素晴らしい。もうほんとこれはすごくいい。これだけでも Test::Unit からの乗り換えに十分値する。
まぁ Test::Unit2 はさらにその上をいくらしいんだけど。
2011-02-27 [長年日記]
_ 今さらRails3メモ - 番外編その1: Paperclip and Dragonfly -
アップロード画像は変遷がいろいろ激しいみたい
画像をアップロードしてそれを表示に利用するのはとてもよくある処理だと思うんだけど、ゼロから実装するのは意外に面倒くさい。でも Rails には便利な plugin があるので大丈夫。
歴史的なことは知らないんだけど、最近は
の二択くらいな感じみたい。どちらも簡単に扱えるけどどっちかというと Dragonfly の方がより簡単で好きかも。ただし今のところ Dragonfly の方が情報は少ないけど。
Paperclip
migration
README から抜粋すると以下の field を持つテーブルが必要らしい。らしいっていうか、実際試してみたんだけど、このエントリ書くまで日が空きすぎて忘れてしまった。
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
Model
上の migration に対応する Model はこうなる。
class User < ActiveRecord::Base has_attached_file :avatar ... end
ここで画像用の attribute は avatar になって、file_name やらなんやらは meta data としていい具合に処理してくれるようになる。
View
こんな感じ。
<%= image_tag @user.avatar.url %> <%= image_tag @user.avatar.url(:medium) %> <%= image_tag @user.avatar.url(:thumb) %>
今回の例は User モデルに avatar 関連の attribute をそのまま載せているが、分離して association でも処理できる。
form 側はこんな感じ。
<% form_for :user, @user, :url => user_path,
:html => { :multipart => true } do |form| %>
<%= form.file_field :avatar %>
<% end %>
単に file_field に当てはめるだけ。
参考
- websymphony/Rails3-Paperclip-Uploadify at master - GitHub
- association を使った簡単な例
- paperclip の保存ディレクトリ名あるいはファイル名をid連番ではなく、MD5とかSHA1のハッシュ値にするメモ - 超自己満足プログラミング
- [Rails] PaperClipを使って本番の時だけAmazon S3を使う - func09
- [rails] paperclipでAmazon CloudFrontを使う - func09
Dragonfly
http://markevans.github.com/dragonfly/
Paperclip のようにはドキュメントや紹介記事を見かけないけど、コードを覗いていくと storage として file, mongo, s3 が使えるみたい。
下準備
config/initializers/dragonfly.rb
require 'dragonfly/rails/images'
migration
最低限一つだけ field があればよいみたい。
class MyMigration < ActiveRecord::Migration
def self.up
add_column :albums, :cover_image_uid, :string
end
def self.down
remove_column :albums, :cover_image_uid
end
end
Model 上でどんな attribute に画像を紐づけるか決めて、
#{attribute}_uid
があれば ok.
Model
上の migration に対応する最低限の Model の記述は
class Album image_accessor :cover_image end
image_accessor で attribute を指定するだけ。すると以下のような感じで meta data を取れる。
@album.cover_image.width @album.cover_image.height @album.cover_image.number_of_colours @album.cover_image.mime_type
View
<%= image.caption %></th>
<%= image_tag( image.photo.process(:thumb, '240x240#').url,
{:size => '240x240', :alt => image.caption} ) %>
こんな風に書ける。
form 側は
<% form_for @album, :html => {:multipart => true} do |f| %>
...
<%= f.file_field :cover_image %>
...
<% end %>
同じ要領ですな。
注意
当たり前だけど image_tag を生成すること。でないと表示されない。
_ しばた [SEO的な意味で便利!というメリットもあります:)]