Categories
open all | close allTags
OpenID | スキンエンジン | モデル | Aptana | パソコン | Subversion | 国際化 | CSRF | rake | テスト | タグ | Migration | Flash | アクセス制御 | 名称 | デュアル・コア | RESTful | ドキュメント | フォーム | 認証Search
思いつきメモ(アイテムやカテゴリーとスキンの紐付け)
アイテム単位でスキンを指定できるとちょっとうれしいかなと思いました。きっかけは卑近なところですが,メインのブログの方で毎月のトップアクセスの記事をまとめているときのことでした。毎月上位に来る記事というのは割と決まっているので,そこが一種のポータル的な役割になるようにページを変えられないかと思ったのです。GoogleのAdSenseなど,内容で広告を動的に変えるものはありますが,全部が自動的に最適になってくれるわけではないし,NP_Relatedみたいなブログ内の関連記事を自動的に探すのもちょっと限界があります。そこでアイテム単位でスキンを変えられると,もっと柔軟な対応ができるかなと思ったわけです。
Twitterでつぶやいてみたところ,カテゴリーもほしいという声も。確かにスキン中のifで制御できるとはいえ,大きく変えたい場合は別スキンに書けるとすっきりしそうです。
実装は二つ考えられます。一つはアイテムやカテゴリーにスキンIDのフィールドを作ること。モデル実装上はこれがきれいで,Nucleus互換エンジン以外にも対応できますが,アイテムごとにまるまる新しいスキンを置くのはかなりおおげさな感じがします。メインと同じスキンの上でできた方が作りやすい。
そこで考えたもう一つの実装はスペシャルスキンパーツを使うもの。例えばitem_333というスペシャルスキンパーツがあったら333というアイテムの表示のときにそれを使います。使い回しはちょっとやりにくくなりますが,それほど多用するものでなければ,これがよさそう。同様にcategory_17などとするとID17のカテゴリー表示にそれを使います。タグも同じようにできると思います。この実装はNucleus互換エンジンだけの機能になってしまいますが,今はこれで実装するつもりです。
思いつきメモ
スキンについての思いつき。Google Groupsに書いたら思い切り文字化けしたのでこっちに転載します。Foodynのスキンにはデータセットという概念があります。例えば
<%dataset(5)%>
とすると,そのページにはアイテムを五つ表示するということになり,ブログやページスイッチでは指定が不要になります。
<%blog(template)%>
<%pageswitch(template)%>
で済んでしまうわけです(templateも省略できますが)。
名前を付けることもでき
<%dataset(name,10,blogname)%>
みたいなことができます(今のところブログ名部分は未実装ですが)。
こうすると,先ほどの指定も
<%blog(template,name)%>
<%pageswitch(template,name)%>
となり,名前付きでないページスイッチと同一ページに共存できます。
データセットの機能は,暗黙的にも使われており
<%blog(template,10)%>
と書くのと
<%dataset(10)%><%blog(template)%>
と書くのは内部的には同じことです。
というわけで実は<%otherblog%>というのはもはや不要だったりするのですが,それはそれとして今日書くのは別の話。
ブログの表示を2段組にしたいとか,トップ二つの記事は要約を付けて,後はタイトルだけにしたいとか(ニュースサイトのように),そういう希望にも応えられるようにしたいと考えています。そのためには同じデータセットの中で表示するアイテムを分割指定できるようにする必要があります。
と,ここまで考えたのですが,どういう指定法にしたら柔軟,かつ簡単に使えるかというところでちょっと思考がストップ中。アイディアをお待ちしております。
サイドバーのウィジェッツ化実装の考察
管理画面のロジックとデザインをできるだけ切り離そうと作業中なのですが,案外難航しています。忙しくて一週間ほど全くプログラムできなかったのもあるのですが,もうちょっとかかりそうです。それはそれとして,アイディアレベルの話ですが,サイドバーをウィジェッツ化できるようにしたいと思ってます。実装としては,
①スキンの中に<%sidebar%>というスキン変数を置くことで,そこがウィジェッツ対応になる。ただし,これはインクルードファイルではなくスキンパーツ(レイアウト含む)の中にないといけない
②<%sidebar(left)%>みたいに名前も付けられる。複数置くときは名前が必須(一つは空でもいい)
③このスキン変数の自体はスペシャルスキンパーツで名前がsidebar(名前付きの場合はsidebar_leftのようにアンダースコアでつなげる)
④標準スキン変数でサイドバー対応のものはパーサのクラスで sidebar :categorylist のように宣言する
⑤これらのスキン変数のために call_categorylist のようにメソッドを用意(なくても動く)。このメソッドはサイドバーで使う名前を返す。メソッドがない場合はcategorylistを言語ファイルで変換
⑥プラグインの場合は event_sidebar を実装することでサイドバー対応になる
⑦event_sidebar はウィジェッツの名前を返す
⑧スキンパーツの編集画面からそのスキンパーツ内のサイドバーを編集する画面を呼び出す
⑨ドラグアンドドロップで編集できる
⑩ウィジェッツの実体は
<div class="sidebar"><h3><%text(プラグイン名)%></h3><div class="プラグイン名"><%プラグイン名%></div></div>
つまり,ウィジェッツ対応のスキンはCSSでクラスsidebarを実装する必要がある。
このほか,対話的にパラメータを変える仕組みを入れたいと思っていますが,そこはまだ詰めていません。
国際化の方法についてのアイディア
Nucleusと同じように定数に言語別の文字列を割り当てて,と考えていたのですが,別の方法を考え中。gettextみたいに,デフォルトの文字列を直接書き入れていき,それに言語ファイルで言語ごとの翻訳を割り当てるといった形。具体的には,これまでの方法だと
「_ADD_NEW_ITEM」
に対して英語だったら
「Add New Item」
日本語だったら
「新規アイテム追加」
といった形で言語ファイルを作っていったわけですが,これだと言語ファイルがなかったり,あっても該当する定数やシンボルに対応する翻訳がないときに,かっこ悪いことになってしまいます。
これを
"Add New Item"
という文字列に対して
英語だったらそのまま,
日本語だったら
「新規アイテム追加」
にするといった形で言語ファイルを作っていく方法が,今考えているものです。これだと,①言語ファイルを作らなくてもデフォルトの文字列でスキンや管理画面を作っていけます。特にスキンやプラグインであれば,デフォルトの文字列を日本語にしておき,それを言語ファイルで英語などに置き換えるといった作り方も許されるでしょう。
Nucleusでは言語ファイル作るのが面倒なのでプラグインのメッセージを英語で作っていたこともよくあったのですが,この方法なら,言語ファイル対応にするためのしきいが低いのではないかと思います。
管理画面作るときも英語のまま作っておいて後から言語ファイルを作るといった作業手順にできるので,これまでのように言語ファイルと平行して作業するといった手間が省略できます。
ただし,難点は二つあって,一つは「シンボル」から変換する形式を取るRailsの標準の国際化機能と相性が悪いこと。もう一つはデフォルト文字列を変えてしまうと,翻訳した文字列を呼べなくなってしまうこと。
前者については,シンプルで実用的でさえあればかならずしもRailsの機能を使わなくてもいいかなと思ってます。言語ファイルは管理画面やスキン,プラグインなどがそれぞれ持つので,サイズもそれほど大きくなく,この設計でも読み込み負荷はあまりないだろうと予想しています。
後者については,デフォルトの文字列を変えたいときはデフォルト文字列の言語用に言語ファイルを用意して,そこで変換させてしまうというのが一つの逃げ道になります。例えば,先ほどの例で「Add New Item」を「Add a Item」に変えたいとしたら,管理画面のテンプレートに書く文字列を変えるのではなく,英語の言語ファイルに
"Add New Item": "Add a Item"
といった形で変換語の文字列を入れる方法です。後は,元の文字列が変わったのだからと割り切って言語ファイルも全部修正する方法。数が少なければ前者もあるでしょうけど,あまりこれをやると訳が分からなくなってしまうので,言語ファイルを修正するのが面倒でも正解かもしれません。
Foodynのディレクトリ構成
Foodynの現状のディレクトリ構成を表にまとめました。Railsが標準で作成するディレクトリとFoodynが独自に作っている部分が分かるように,Railsによるディレクトリは黄色で示しています。ディレクトリ構成
以下ではFoodynをいじる人が必要になりそうな部分を説明します。
libのnc_parserがスキンやテンプレートを解釈実行する部分です。parse_xxxといったメソッド名はNucleusを踏襲しています。このディレクトリの中ではbase.rbが汎用のパーサー用メソッドなどを持つベース部分で他のクラスはこれを継承します。なお,Railsの命名規約に合わせて,nc_parserのbase.rbには「NCParser」モジュールの「Base」クラス,すなわち「NCParser::Base」を定義しています。こうしておくことで,アプリ内の他の部分からNCParser::Baseが呼び出されたときに,そのクラスが事前にロードされていなくても,Railsが必要なファイルを見つけてくれます。requireなどを書かずに利用できるわけです。
default_skin_parserはスキンタイプ共通のメソッドを集めており,スキンタイプごとのパーサーは,その子クラスになります。このほかテンプレート,テンプレート・コメント,アイテムをパース実行するクラスがあります。
なお,ここにskinsというサブディレクトリがありますが,使用予定はありません。無視してください。
app/modelsにデータを操作する部分がまとまっています。RailsにおけるMVCのM(モデル)であり,データベースのテーブル一つが一つのクラスに相当します。Railsではクラス名からテーブル名も自動的に決められて設定なしにアクセスできるのですが,テーブル接頭辞とテーブル名の語幹部分の設定を両立できないため,Foodynではテーブル名をモデルごとに明記する必要があります。例えばitem.rbでは「set_base_name :item」という記述が先頭のほうにあります。これでitemテーブルにアクセスします。接頭辞部分はconfig/database.yml内に記述するようにしています。productionとdevelopmentで接頭辞を変えたいといったことに簡単に対処するためです。
また,Railsではテーブル内のidという名称のフィールドをプライマリ・キーとして使用します。プライマリ・キーがないテーブルは書き込みできないなど使用に大きな制限が出るため,FoodynではNucleusが単独フィールドのプライマリ・キーを設けていないテーブルにもidフィールドを加えています。またitemテーブルのinumberなど,id以外の名称のプライマリ・キーがある場合は「set_primary_key :inumber」という指定をします。
モデルによっては内部に多くのロジックを持っています。代表的なのがitem.rb。クラスメソッドのget_listはアイテム一覧を得るための汎用的なメソッド。ページ名や1ページのアイテム数,カテゴリーやタグなどに対応しており,呼び出す側が拡張できるようにもなっています。例えば:orderを指定することでアルファベット順にリストを得るといったこともできます。インスタンス・メソッドのhas_rightは現在のユーザーが特定の権限を持っているかどうかを調べるメソッド。管理画面作成時などに必要になります。
blog.rbとmember.rbの中にもhas_rightというメソッドがあります。管理画面ではmemberに対してhas_rightで権限があるかどうかを調べます。そうするとblogやitemなどに対して権限を調べてもらうためにそれらのhas_rightが呼び出されます。
管理画面に関連するのはviewsのところですが,これについては項を改めて説明します。
ページスイッチ部分の仕様
Foodynの公開をしてから,そういえばカテゴリー部分のクエリーを実装していなかったことに気付き,作業中です。それだけならたいした手間ではないのですが,以前から頭のどこかにあったページスイッチ部分を実装しようかと思い,遠回り中です。ページスイッチは,NucleusだとShowBlogsが生成するものをそのまま使っている人が多いと思いますが,ここのページにあるようないろいろなデザインができないのが残念なところ。また,配置もアイテム表示の直前か直後に固定されてしまいます。
ページスイッチを表示するスキン変数を別途用意すればいいのですが,表示内容の指定などをblog変数に合わせないといけません。そこで,Foodynではデータセットという概念を導入して,二重指定を不要にしようと思っています。ページスイッチのスキン変数かblog変数かどちらか先に指定したものの表示内容(1ページに表示するアイテムの数など)をデータセットとして,他方はデータの指示なしに表示できるようにします。表示機能なしで,データセットの指定だけするスキン変数も用意します。
頭の中では,この機能を応用して,1ページ内に複数のページスイッチを別の用途で置けるようにする実装もできているのですが,ちょっと面倒な点がいくつかあるので,後でやることになると思います。
なお,テンプレートのデフォルト値やインライン・テンプレートのアイディアはページスイッチのスキン変数を考える際に思いついたもの。脈絡ないようですが,実はあるのです。
テンプレート機能を使いやすくする
Nucleusの柔軟性を高めているのと同時に分かりにくいと言われる原因でもあるのがテンプレートのところだと思います。一つのテンプレートの中にも,アイテム表示に関連する部分,カテゴリーリストに関連する部分,コメントに関連する部分,画像表示に関連する部分など,いろいろな部分があることがさらに分かりにくさに拍車をかけています。Foodynでは二つの新しい機能を使ってこの部分を少し使いやすいものにしようと考えています。一つはデフォルト機能。「conifg/default_template.yml」というYAMLのファイルを用意し,それに各テンプレート・パーツのデフォルト値を置けるようにします。これによって,テンプレート指定なしでも,全く表示がないといったことがなくなります。
もう一つはインライン・テンプレートの機能。どちらかというとプラグインなどからの利用を想定していますが,YAMLの表記ルール(あるいはJSON)を使って,ユーザーが利用できるようにすることもあり得るでしょう。これはデータベースにテンプレートを入れなくてもテンプレート機能を使えるようにするもの。例えばプラグインからパラメータによって,テンプレートを変えて出力するといった使い方が簡単にできるようになります。ユーザーレベルではスキンにこれを記述できるようにすると,テンプレートなしで書けるようになります。そちらは実装するかどうか未定。
Railsの国際化機能
Rails2.2に国際化の機能が入ることになったので,Foodynでもそちらを使う方向で考えることにしました。これまで使う予定だったSimple Localizationも開発を終了するとのことです。というわけで,そこをはずしたりしてSubversionのプラグイン・ディレクトリをいじっていたら,うっかりしてサンプルプラグインを消してしまいました。まあ大部分のことはこのブログ中に書いてあるのでいいのですが,ちょっとショック。管理画面設計中
とはいっても,まだやっているのはフリーの管理画面デザインをRailsのヴューに当てはめているだけ。中身はまだ空です。それとは関係ないけど一つメモ。Foodyn CMSは複数ユーザーで安全に運用できることを目指していますが,スキンの扱いで一つ考えなければいけないところがありました。例えば,あるユーザーがスキンを選んでカスタマイズする場合,それは他のユーザーには波及しないようにしないといけません。つまり,ブログごとにスキンの複製を作ってからカスタマイズすることになります。また,こういったスキンはブログを消去した際に一緒に削除しないといけません。
Foodynでは,スキン・エンジンごとにduplicateを使うかどうかを設定できるようにしようと思っています。まだその辺の処理は組み込んでいませんが,一応覚書として。
アクセス制御の枠組み
アクセス制御のためのデータ構造が大体決まりました。たぶんこれで行けるでしょう。
ちょっと分かりにくいので図にしてみました。
アクセスはロールごとに決めますが,ロールにはシステム・レベルのものとブログ・レベルのものがあります。システム・レベルのロールはmemberテーブル内に書きますが,ブログ・レベルのものはteamテーブルで指定します。本当は権限については独立したテーブルを用意し,中間テーブルを作ってマッチングさせるのが拡張性が高いのですが,実行速度を重視して,ロールのテーブル内のフィールドとして各権限を設定するようにしました。また,ブログレベルのロールとシステムレベルのロールを区別するためのissystemというフィールドを作っています。このほか,アイテム単位で制御方法を変えられるようにするためにアイテムとロールによるテーブルも作ります。
クエリーの効率が心配ですが,たぶんこれでやりたいことはできる枠組みではないかと思います。