Categories
open all | close allTags
カテゴリ | rubygems | CSRF | パソコン | Aptana | スキンエンジン | 国際化 | デュアル・コア | JustPosted | Flash | フォーム | タグ | テスト | 認証 | Subversion | RESTful | Migration | 名称 | rake | ドキュメントSearch
ブログRole追加だけで終わってしまった
システム系はどういうRightsが必要か考えるのが結構大変だ。でもやっておかないとね,後から拡張するんでもいいけど。
アクセス制御の枠組み
アクセス制御のためのデータ構造が大体決まりました。たぶんこれで行けるでしょう。
ちょっと分かりにくいので図にしてみました。
アクセスはロールごとに決めますが,ロールにはシステム・レベルのものとブログ・レベルのものがあります。システム・レベルのロールはmemberテーブル内に書きますが,ブログ・レベルのものはteamテーブルで指定します。本当は権限については独立したテーブルを用意し,中間テーブルを作ってマッチングさせるのが拡張性が高いのですが,実行速度を重視して,ロールのテーブル内のフィールドとして各権限を設定するようにしました。また,ブログレベルのロールとシステムレベルのロールを区別するためのissystemというフィールドを作っています。このほか,アイテム単位で制御方法を変えられるようにするためにアイテムとロールによるテーブルも作ります。
クエリーの効率が心配ですが,たぶんこれでやりたいことはできる枠組みではないかと思います。
またもやわき道にそれる
管理画面のUIを考えているのですが,そのときにどうしてもアクセス制御のところを入れておかないと気持ち悪くて先に進めません。Foodyn CMSではロール・ベースのアクセス制御を採用する予定です。大体のアイディアはあるのですが,基本的な仕組みのところは作っておかないと管理画面のコーディングができません。簡単なロール・ベースのものなら,世の中にいくらでもサンプルがあると思います。それを使うのも一つの手ですが,今考えているのはブログのチームの概念と組み合わせた制御ができないかどうか。
例えばAというブログがあって,a,b,cの3人がメンバーだとします。またBというブログがあってc,d,eの3人がメンバーだとします。このときにcはAではadminだけどBでは閲覧しかできない,といったアクセス制御をどうやって実現すればいいのか。また,aはAでアイテムが追加できるユーザーで,dはBでアイテムが追加できるユーザーだったとき,この二人を同じロールにできるのか。結構めんどくさそうです。
UI考え中
やみくもに末端の機能から作っていこうかみたいなことも考えたのですが,やっぱりここは肝なのでちゃんとユーザー・インタフェースを考えてから作ろうと,珍しく画面設計からはじめています。しばらくはコーディングともおさらばです。
タグとカテゴリが曲がりなりにも動いたので
そろそろ次のフェーズ(管理画面)に入ろうかと。あー腰が重い。
まずは投稿画面からかな。
ちょっと付け焼刃ですが一応TagCloud完成
スキンからは<%TagCloud(default/index,10)%>みたいな感じで呼び出します。パーサーでは
def parse_tagcloud params
blog = params[3] ? Blog.find_by_bname(params[3]) : @controller.blog
templatename = params[1]
template = Template.find_by_tdname(templatename)
bd = blog.basic_data
data = Hash.new
tempbuffer = fill(template['TAGLIST_HEADER'], bd)
tags = Category.tags(blog.id, params[2].to_i)
max = tags.first.count.to_i
min = tags.last.count.to_i
maxlevel = (params[4] || 4).to_i
if max == min
factor = 0.0
else
factor = (maxlevel - 1).to_f / (max - min)
end
tags.each do |tag|
data['level'] = Math.sqrt((tag.count.to_f - min) * factor).to_i + 1;
data['taglink'] = url_for(:controller=>'categories', :catid=>tag.catid, :action=>'show')
data['tagname'] = tag.cname
data['count'] = tag.count
tempbuffer += fill(template['TAGTLIST_LISTITEM'], bd.merge(data))
end
tempbuffer += fill(template['TAGLIST_FOOTER'], bd)
return tempbuffer
end
ここでCategory.tagsで指定した数だけタグをカウント順に取ってきます。この最大値と最小値から,比率を求めて大きさ(テンプレート中で<%level%>)を決めます。
Category.tagsの方が,苦労したところ。
def self.tags blogid, limit = nil
if limit
find(:all, :joins=>('LEFT JOIN '+TagCategory.table_name+' on catid=category_id'), \
:conditions=>['cblog = ? and caliasid is not null', blogid], \
:group=>'catid', :select=>'*, count(*) as count', :order=>'count DESC', \
:limit=>limit.to_i)
else
find(:all, :joins=>('LEFT JOIN '+TagCategory.table_name+' on catid=category_id'), \
:conditions=>['cblog = ? and caliasid is not null', blogid], \
:group=>'catid', :select=>'*, count(*) as count', :order=>'count DESC')
end
end数を限定する場合としない場合で分けてあります。これでSQL文一回呼び出すだけでカウントが取れます。
今の仕様だと,カウントが多い順にしか出力されないところがいまいちです。リストを取ってきた後ランダムに並べ替えるようなことができるといいのですが。
表示されていないだけで
countはちゃんと取れていました。ただし型がStringになる点に注意が必要です。Integerにする方法はないのかな?
:joinsに変えたら
SQLは正しく発行できているのを確認しました。でもオブジェクトとしてcountが取れていないみたい。どうしてかちゃんと調べようとしたところで昨晩はダウン。今週は仕事が忙しいのでさすがに疲れ気味です。
:includeと:selectは共存できない
まだTagCloudではまっているのですが,何かというとタグクラウドを作るためにはタグごとに使われているアイテム数を調べる必要があるのです。タグごとに調べるのであればActiveRecord使って簡単に書けますが,どうみても効率が悪そう。SQL文一発で実行したいのです。group byしてcount取れば行けるのはSQLレベルでは確認したのですが,なかなかRailsでうまく行きません。生成したSQLを見るとselectにcountが入っていません。
さらに理由を調べると,どうやら:includeオプションを使うと:selectは使われないそうな。:includeは結構膨大なテーブル検索をかけるのでこれも効率悪そうなので,:joins使って実現することにします。テーブル名を直接指定しないといけないのでちょっと面倒ですが。
TagCloudがめんどくさい
探せばタグクラウド作るプラグインくらい,あるんでしょうけど,下手な作り方をすると結構効率が落ちそうな気がするのでなるべく自前でやろうとしています。アルゴリズムが難しいわけではないのですが,クエリーが結構複雑なので,なかなか手が進みません。がんばれ>自分