Categories
open all | close allTags
認証 | OpenID | テスト | RESTful | CSRF | 名称 | nextlink | カテゴリ | 抽象化 | モデル | プラグイン | スキンエンジン | Migration | タグ | rake | フォーム | デュアル・コア | Aptana | アクセス制御 | パソコンSearch
初めての管理画面(笑)
とりあえず前言撤回で,RESTfulで用意されているもので大体なんとかできそうな感じがしてきました。deleteのユーザー・インタフェースなど,気になるところもありますが,まずは標準機能で実装していきたいと思います。で,一応今の管理画面。(管理画面)
URLは全部ではないですが,ちゃんとしたものを生成しています。
ここではメモとして,map.namespace付きのprefix付き,ネスティッド・リソースという“テンコ盛り”状態でのルーティングについて書いておきます。
map.namespace(:admin) do |admin|
admin.root :controller =>'admin'
admin.connect ':memberid', :controller =>'Admin'
admin.resources :blogs, :path_prefix=>'admin/:memberid' do |blog|
blog.resources :items
blog.resources :comments
blog.resources :categories
end
admin.resources :plugins, :path_prefix=>'memberid'
endというのがルーティング部分(まだ完全ではありません。必要なとこしか作ってないので)。ここでルートのコントローラを指定することで,アドミン用のコントローラはadminディレクトリの下から選ばれるようになります。アドミンへのアクセスは全部認証付きであり,認証されたユーザー名がmemberidになります。したがって'admin/:memberid'が管理画面のルートです。
その下のresourcesの部分が今日の骨子。ブログ周りのリソース定義をしています。RESTfulなルーティングを使うためにはresourcesが必要です。ここでちょっと注意が要るのがpath_prefixのところ,ここは本来':memberid'だけでいいはずなのですが,それだとURLを生成したときにadminが抜けてしまうバグ?があります。そこでわざわざこれを入れています。
以下でネストされたリソースを加えています。
URLを生成するときはリソースを指定する必要があるのですが,この場合,例えばアイテムの一覧を表示したかったら「admin_blog_items_url(@memberid, blog)」といったリソースをurl_forやlink_toなどのメソッドに渡します。ここで@memberidがユーザー名ですが,これをパラメータに入れるのも一つの肝。プレフィクスを指定しているからなのでしょうけれども,そのあたりの説明はドキュメントになく,試行錯誤で見つけました。なお,admin_blog_items_urlというメソッド名は「rake routes」でルート定義の一覧を出すと分かります。例えば今の部分は
admin_blog_items GET /admin/:memberid/blogs/:blog_id/items {:controller=>"admin/items", :action=>"index"}
といった形で記述されています。これで,今度はAdmin::ItemsControllerのindexメソッドを用意すればいいことが分かります。
これで後はスピードアップするかな?
ダック・タイピング
アイテムでもブログでも区別しないで権限を調べられるように,両者に同じメソッドを作ってアクセスするようにしています。これもダック・タイピングと呼んでいいのかな?先日デザインパターンの本を読んだのですが,なかなかおもしろかった半面,記述がJavaだったため,Rubyだとどうなるのだろうと気になるところもありました。Javaではインタフェースを中心にデザインパターンを構築することが多いようですが,Rubyだとインタフェースという機能はありません。その代わりにmoduleを使ってミックスインしたり,今回のように特に宣言なく同じAPIを用意して呼び出すといったことができます。こういった特質により,デザインパターンの実装も変わってくると思います。
Web上にはまつもとさんが書かれたものも含め,いくつかRubyによるデザインパターンの実装がありますが,できたら体系だって本として読みたいところ。
:includeと:selectは共存できない
まだTagCloudではまっているのですが,何かというとタグクラウドを作るためにはタグごとに使われているアイテム数を調べる必要があるのです。タグごとに調べるのであればActiveRecord使って簡単に書けますが,どうみても効率が悪そう。SQL文一発で実行したいのです。group byしてcount取れば行けるのはSQLレベルでは確認したのですが,なかなかRailsでうまく行きません。生成したSQLを見るとselectにcountが入っていません。
さらに理由を調べると,どうやら:includeオプションを使うと:selectは使われないそうな。:includeは結構膨大なテーブル検索をかけるのでこれも効率悪そうなので,:joins使って実現することにします。テーブル名を直接指定しないといけないのでちょっと面倒ですが。
Aptanaのデバッグ問題ようやく解決
めんどくさがらずに早くフォーラムで聞けばよかった。http://forums.aptana.com/viewtopic.php?p=20870#20870
DreamHostでpassenger(mod_rails)サポート
米国の有名なホスティング・サービスDreamHostで,passenger(aka mod_rails)がサポートされたそうです(ブログ・エントリ)。これがあるとRailsアプリをホスティングで動かすのがPHP並みに簡単になるとか。使ってみたいですねえ。といってもまだ今のホスティングでもRailsアプリ動かしていないのですが(今のところ実験はローカルだけ)。このホスティングではまだアナウンスがありません。多分テストはしているのでしょうけど。
DreamHostは年間100ドル近い割引のクーポンが出回っているので,1年だけテスト用に借りるというのはあるでしょうね。悪評も多いところなのでメインに使うのはちょっと不安ですが。
設計とメソッド名と内部構造
どうも頭がまだ手続き型言語から抜けていないようで,メソッド名を付けるときに,ついつい「get~~」みたいに動詞を入れてしまいがちです。ということに気付いたのは,あるブログに属するカテゴリー一覧を取得するとき。実はこれまでCategoryクラスの方でget_listというメソッドを作ってブログオブジェクトをパラメータに取得するようにしていました。こうしておくと,ブログが指定されないときの一覧やブログが複数あるときの一覧とかも同じメソッドで取れるというのがメリットなのですが,見直してみるとCategory.get_list ... と入るのはあまりきれいじゃないです。やはり blog.categories と書いた方がスマート。
これだと順序付けができないのかと思って,この記述を使っていなかったというのもあるのですが,APIを見たら has_many のリレーション指定の中で :order を使って指定できることが分かったので,今回はそちらに切り替えました。
ただ,しっくりこない面がないわけではありません。これだとBlogクラスの中でCategoryのテーブルの内部情報を使って :order のところを書くことになるため,Categoryの実装に完全に依存してしまいます。Categoryの内部構造が変わったらBlogクラスも変えなければいけないのでメンテナンス性が悪くなります。
どうするのがベストなんでしょう。
美しくない解決法
いろいろ調べるうちに,FoodynPlugin::Baseというクラス・オブジェクトが二つ存在していることが分かってきました。「なんてこった」って感じです。クラスはシングルトンじゃないんでしょうか。愚痴りたい気持ちはやまやまですが,とにかく動くようにすることが先決なので,なんとか解決法を考えました。
def self.list
@pluginlist ||= Array.new
if @pluginlist.size == 0
@pluginlist = Class.constants.select do |c|
cclass = c.constantize
if (cclass.is_a? Module) && (cclass.constants.include? 'Base')
klass = (c+'::Base').constantize
klass.ancestors.any? {|anc| anc.name == 'FoodynPlugin::Base'}
end
end
end
@pluginlist
end
def self.plugin_class plugin_name
if (pl = list.find {|p| p.downcase == plugin_name.downcase})
return (pl + '::Main').constantize
end
end
プラグイン・クラスの一覧を取るアルゴリズムですが,まずはClassレベルにおける定数を調べ,そこでModuleに属するものを選び,さらに,Module内の定数で「Base」を含んでいるものを選びます。この中から,Base付きのクラスの先祖のクラスを調べ,そこにFoodynPlugin::Baseがあるかどうかで判断しています。本来ここはクラスレベルで判定できるはずですが,上記の理由によって,わざわざ文字列に変換して比較しています。
美しくはありませんが,ともかくこれでスキン変数が動くようになりました。なんだかどっと疲れました。
Agile Web Development with Rails, Third Editionのβが出た
Railsのバイブル的本である「Agile Web Development with Rails」の第3版がβ版(PDF)として出ています。Rails2に対応した本格的な解説書としては初めてのものなので,これは間違いなく「買い」でしょう。日本語版が出るのを待ってはいられないので,英語のPDFを購入しました。PDFのサイズ8Mバイト,750ページという大著です(第2版は719ページ)。
テスト
プラグインの動作関係をちゃんとテストを書いて検証しようと思っているのですが,これまで手動テストばかりやっていたので,テストの書き方を全く覚えていません(泣)。この機会にちゃんとしたいところ。プラグインの雛形もgeneratorで生成できるようにしたいのですが,ちょっと面倒なので,もっと仕様が落ち着いてから手を付けることになりそうです。
migrationでインデクスを生成させていたら,「名前が長すぎる」というエラーが。インデクスに使うカラム名を名前に入れていくので,カラムが複数とかになるとすぐに長くなってしまいます。とりあえずテーブル名などを短くすることで対処しましたが,名前設定てできるのかな?
RESTful Webサービス
オライリーから出ている「RESTful Webサービス」を読みました。現在のところRESTfulなアプリケーションの作り方について,まとめられているものとしては一番詳しいと思います。タイトルにあるように,主体はWebサービスの設計。FoodynのようなWebアプリケーションについての記載はあまり多くはありません。それでも,これまで考えてきたことを改めて整理したり,RESTfulな考え方をなじませるためにはかなり役に立ったような気がします。例えば,トランザクション処理は,これまでステートレスであるRESTfulにはなじまないものと思い込んでいましたが,トランザクション自体をリソースとして処理する方法が挙げられており,これには目から鱗が落ちる思いがしました。
例として挙げられているコードはほとんどがRuby on Railsなので,読者もRubyとRailsが分かることがある程度要求されそうです。Ruby知らなくても概ね雰囲気はつかめると思いますが。
RESTfulなWebサービスやアプリケーションを開発する人にとっては一度は読むべきものだと思います。
RESTful Webサービス
Leonard Richardson、Sam Ruby、山本 陽平、株式会社クイープ
オライリー・ジャパン
2007/12/21
¥ 3,990 (定価)
¥ 3,990 (Amazon価格)
39pt (Amazonポイント)
(私のおすすめ度)
★★ (Amazonおすすめ度)
単行本
通常24時間以内に発送
(価格・在庫状況は7月5日 14:32現在)
Leonard Richardson、Sam Ruby、山本 陽平、株式会社クイープ
オライリー・ジャパン
2007/12/21
¥ 3,990 (定価)
¥ 3,990 (Amazon価格)
39pt (Amazonポイント)
(私のおすすめ度)
★★ (Amazonおすすめ度)
単行本
通常24時間以内に発送
(価格・在庫状況は7月5日 14:32現在)
