Monster Debugger – Flex開発のお供に
この2週間ほどFlex4でクライアントサイド書いているわけですが、いくつか階層を重ねたコンテナの上部に、paddingTop=”0″にしているのに妙なpaddingが空いたりとかで、Firebug的なものが欲しいなーと思って探したらちょうど良いのがありました。
インストールしたらAirアプリケーションとして立ち上がります。
プロジェクトタイプなどを選んでExportすると必要なswcが出力されますので、それに対してFlexプロジェクトのライブラリパスを通してあげます。
後は、キャプチャにもあるように
ライブラリをインポートして
import com.demonsters.debugger.MonsterDebugger;
初期化するだけです。
MonsterDebugger.initialize(this);
MonsterDebuggerを開いた状態でプロジェクトを実行すると、デバッガに接続されてこんな感じになります。
Highlight & Inspectをクリックして、画面から要素を選択してオブジェクトのプロパティを確認したり、そのプロパティをLiveに変更したりなど。
またconsole.log的にオブジェクトのダンプも含めたログを吐いたりなどもさくっとできます。
MonsterDebugger.trace(this, "Hello World!");
いろいろと助かりそうです。感謝。
「夏だ!Rubyだ!RBC Nightだ!!Rubyで作ったスマホアプリってどうなの??」な話
muraveです。Rubyビジネス・コモンズ(RBC)というコミュニティのスタッフもしています。
「夏だ!Rubyだ!RBC Nightだ!!Rubyで作ったスマホアプリってどうなの??」というイベントが6/22(金)の夕方から開催されました。RBCでは毎月土曜日に1日、または半日規模の勉強会を開催してきたのですが「もっとフランクにいろいろやっていこう」ということになりました。このイベントはその1回目です。
長崎から福岡での金曜日夕方のイベントへの参加はちょっとキビシイですが以前からリクエストしていたRhodesでのスマホアプリ開発ネタとなれば行くしかありません。
イベントでは実際にRohdesで開発された新感覚スマホ式カードラリー『る〜ら』について技術とビジネスのお話を聞くことができました。技術寄りのお話をしていただいた古川さんのスライドはslideshareで公開されています。
http://www.slideshare.net/purukyawa/rubyrbc-nightruby
苦労はされてますが「機能制限は必ずある」のだから「制限を理解して提案、設計」してちゃんとチューニングすれば「決して遅くない!!」とのこと。
最近だと機能優先で進めてから速度のチューニングをすることが多いですが、回線や端末の速度に制限があるスマホのような環境では最初から速度のことを考えつつ進めたほうがいいのかもしれないな、と思いました。
ビジネス寄りのお話では実際のユーザー数のお話、さらに懇親会では投下資金のお話などもでてエキサイティングでしたが、ココら辺は参加者特権ということ秘密。
次はRubyでスマホアプリの第2弾、ネイティブiPhoneアプリが開発できるRubyMotionについてのイベントを7/20に開催予定です。
あと、9月は私が担当でイベントをやる予定です。長崎で。
まだ何をするか決めてませんがそのときはよろしくお願いします。
ところで、RBCのオフィシャルサイト、古いページがのこってしまっていてややこしいんですがfacebookのページがそうなんです。
http://www.facebook.com/rubybizcommons
最新情報については上記URLからお願いします。
baserCMSの認証をカスタマイズ(WordPressのアカウントでログイン)
baserCMSのバージョンは2.0.1です。
現在弊社のサイトはbaserCMSとWordPress(スタッフブログ)が同居しています。
アカウントの管理を統一したかったのでbaserCMSにWordPressのアカウントでログイン可能なようにbaserCMSの認証をカスタマイズしました(先にWordPressを運用していたのでスタッフのアカウントがWordPressにありますので)。
次のような仕様にしました。
- WordPressのアカウントでbaserCMSにログインした場合、事前に作成したstaffアカウントとしての操作になる。
- 公開ページで表示される名前(氏名)はstaffとする。
- ログイン中、氏名を「staff(WordPressアカウント)」とする。
- 誰が操作したかの記録は欲しいのでダッシュボードの「最近の動き」に by 氏名 と付加して記録する。
baserCMSの認証はbcAuthComponent(baser/controllers/components/bc_auth.php)に切り出してありますので、このファイルをappディレクトリの同一階層にコピーしてそのファイルを修正します。元のbcAuthComponentは携帯の簡単ログイン対応になっていたのですが携帯でのログインは必要なかったので全部削除して書き直しって感じになりました。
app/controllers/components/bc_auth.php
App::import('Component', 'Auth', 'Sanitize');
class BcAuthComponent extends AuthComponent {
//WordPressアカウントでstaffとしてログイン murave
function login($data = null) {
$this->__setDefaults();
$this->_loggedIn = false;
$wordpress_id = null;
if (empty($data)) {
$data = $this->data;
}
$model =& $this->getModel();
$alias = $model->alias;
$cnt = $model->find('count',
array('conditions' => array($this->userModel . '.' . $this->fields['username'] => $data['User']['name'])));
if($cnt == 0) {//baserCMSには存在しないユーザー
if($this->_wp_CheckPassword($_POST['data']['User']['name'], $_POST['data']['User']['password'])) {
$wordpress_id = $_POST['data']['User']['name'];
$staff_record = $model->find('first',
array('conditions' => array($this->userModel . '.' . $this->fields['username'] => 'staff')));
$username = $staff_record[$this->userModel][$this->fields['username']];
$password = $staff_record[$this->userModel][$this->fields['password']];
$data = array(
$this->userModel . '.' . $this->fields['username'] => $username,
$this->userModel . '.' . $this->fields['password'] => $password
);
}
}
if ($user = $this->identify($data)) {
if(!is_null($wordpress_id)) {
$user['real_name_2'] = '('.$wordpress_id.')';
}
$this->Session->write($this->sessionKey, $user);
$this->_loggedIn = true;
}
return $this->_loggedIn;
}
/**
* WordPressユーザー認証を行う。
*/
private function _wp_CheckPassword($wordpress_id, $password) {
//WordPressの関数を使って認証を行ない結果をtrue/falseで返す処理です。
}
}
_wp_CheckPasswordがWordPressに認証させる処理で「肝心な所」ではあるのですが、環境によって異なるはずなので申し訳ありませんが割愛しています。
baserCMSにアカウントが無かったらWordPressに認証させて、WordPressで認証に成功したらstaffというアカウントでbaserCMS側は認証、その場合には $user[‘real_name_2’] = ‘(‘.$wordpress_id.’)’ とreal_name_2に設定してからセッションに書き込んでいます。real_name_1はstaffにしているので操作中の氏名は「staff(WordPressアカウント)」となります。
次に「最近の動き」への記録ですがBaserAppModelのsaveDbLogメソッドで行われていますのでこのメソッドの動作を変更します。baser/models/app_model.phpをappディレクトリの同一階層にコピーしてメソッドを定義すれば上書きできます。
app/models/app_model.php
class AppModel extends BaserAppModel {
function saveDbLog($message) {
// ログを記録する
App::import('Model', 'Dblog');
$Dblog = new Dblog();
$logdata['Dblog']['name'] = $message
.' by '.@$_SESSION['Auth']['User']['real_name_1'].@$_SESSION['Auth']['User']['real_name_2'];
$logdata['Dblog']['user_id'] = @$_SESSION['Auth']['User']['id'];
return $Dblog->save($logdata);
}
}
これで当初予定していたカスタマイズが一通り完了しました。baserCMSはカスタマイズしやすくていいですね。
baserCMS 2系で追加されたテーマヘルパーが便利(だけど要注意)
本日の「忘れないうちに書いとくぜ!baserCMSネタ」のお時間がやってまいりました。
baserCMS 2系でテーマヘルパーが追加されました。
http://basercms.net/functions/theme_helper
弊社サイトはlancardというテーマを作ってその下で構築しています。
現在、その中で、これから追加や編集をしていく予定があり、書き方が複雑だけど規則性がある、「ホームページのピックアップ(上部の画像切替)」と「ウィジェットのバナー表示」についてテーマヘルパーを利用して更新コストを下げています。
参考に、バナー表示用のヘルパーのコードを抽出して貼ります(ピックアップについては複雑なので)。
app/webroot/themed/lancard/helpers/lancard.php
BcBaser->getUrl('/themed/lancard/img/bunner/'.$imgFile, true)
.')';
$this->BcBaser->link(
$title,
$url,
$linkAttributes
);
}
}
?>
使用方法はこんな感じ。
bunner('OSSダウンサイジング', 'downsizing.jpg', '/it-model') ?>
と書くと
OSSダウンサイジング
と出力されます。便利です。
しかし、このテーマヘルパー、注意して扱わないと大変ヒドイ目にあいます。
テーマヘルパー用のディレクトリに「正しいテーマヘルパー以外のファイル」を置くとサイトのルーティングが全滅します。管理ページもアクセス不能! 初めてこの現象に遭遇したときは超ビビリました。
ヘルパーを読み込もうとしてエラーが発生するわけですが、その影響範囲が想定の範囲外!
私がやってしまったパターン
- テーマヘルパー開発中に動作確認しようとしたらサイトが全滅してた。
- テーマヘルパーを更新するときに旧ファイルをlancard.php_oldとリネームしたら全滅。
いかがでしょうか。恐ろしいですね。
しかしこの副作用、次のチケットでかなり解決しそうですので一時的な問題だと思います。
TODO #2604 「テーマヘルパの読み込みはテーマ名のヘルパのみにする」
そうそう、ヘルパー名は上記チケットの内容にしたがってつけておきましょうね。
baserCMSのサイトマップをカスタマイズ
baserCMS のバージョンは 2.0.1 です。
baserCMSにはサイトマップを出力するヘルパーがあって、
sitemap() ?>
と書くと固定ページについてはサイトマップを自動で更新してくれて便利です。
なのですが、いろいろと不満もあるヘルパーです。
- 固定ページ以外(Blogとかメールフォーム等)はダメ。
- カテゴリのindexにページ名をつけるとカテゴリとページで同じURLが表示されてダブる。
てなわけでカスタマイズしました。
baser/views/helpers/bc_baser.php を読んでヘルパーの仕組みを調べると再帰的にページをたどっていること、テンプレート baser/views/elements/sitemap.php を使用していることが分かりました。
検討した結果、「固定ページ以外はダメ」に関して根本的な解決は出来ないのですがテンプレートのカスタマイズで対応することにしました。
データの取得方法から変更した独自ヘルパーの作成も考えたのですが、結局どこかに「Blogやメールフォームを何処に表示するか」という情報を持たせなければならないので完全自動化はできない。それならデータ取得は既存の方法を使って必要な追加設定はテンプレート内で配列にでももたせるか、と。
まず、baserCMS カスタマイズの常道としてbaserディレクトリのファイルを自分のテーマの同階層にコピー。これでコピーしたファイルが有効になるのでこのファイルを改造していきます。
改造した結果、こうなっちゃいました。
//ここから設定
//表示しないurl
$disables = array(
'/index_test',
);
//$inserts = array(before_url=>array(title, url),,,)
//before_urlの次に挿入url,titleで作成したアイテムを挿入
//ブログ、メールフォームなどpage以外を途中に挿入することが出来る。
$inserts = array(
'/sitemap' => array('新着情報', '/news'),
'/news' => array('お問い合わせ', '/contact'),
'/it-model/faq' => array('ダウンサイジングについてのお問い合わせ', '/contact_itmodel'),
);
//設定ここまで
//関数
$outputPageItem = function ($recursive, $title, $url) use (&$bcBaser) {
?>
-
element('sitemap', array(
'pageList' => $pageCategories['children'],
'category_title' => $category_title,
'category_url' => $category_url,
'recursive' => $recursive+1
));
endif;
if($outputed_category_li):
$outputCategoryItemTail();
endif;
endforeach;
endif; ?>
「カテゴリのindexにページ名をつけるとカテゴリとページで同じURLが表示されてダブる」のは解消。
追加設定に特定ページを表示したくない時のための$disables配列、Blogやメールフォームを思い通りの場所に挿入するための$inserts配列を用意することで希望する表示ができるようになりました。
しかし、元テンプレートからかけ離れているのはともかくとして、
basercmsのエレメント内で無名関数を定義して再帰呼び出しやってやったぜ〜。ワイルドだろ?
— murave (@murave) June 15, 2012
てなことをやってるので万人にはオススメできない。無名関数を使っているのでPHP5.3以降限定ですし。
関数を定義したのは「処理をパーツ化しないとコードがあまりにもカオス」「処理を再帰呼び出しする必要があった」からです。
無名関数を使ったのは「関数の影響範囲を限定したかった」から。テンプレートが複数回呼び出しされるので関数の再定義エラーがでるという問題もありましたが、これは無名関数にしなくても未定義の場合のみ関数を定義するようにすれば回避できると思います(試してませんが)。
baserCMSのfeedプラグインで既存フィードを合成したフィードを作成
baserCMSでリニューアルした弊社サイトですが、このスタッフブログはWordPressのまま残しました。
そうなるとサイトのフィードはbaserCMSで運用している新着情報とWordPressで運用しているスタッフブログの両方の情報が入っていて欲しい。「両方のデータベースからデータさらってきてフィードを作るプログラムでも書くかなー」などと調査したりしていたのですが、気づきました。
「feedプラグインで合成表示は出来るんだからRSSのフォーマットで出せばいいんじゃね?」
てなわけで、現在弊社のフィード(RSS 2.0) http://www.lancard.com/rss はfeedプラグインでbaserCMSのBlogのフィードとWordPressのフィードを合成して作成しています。
どうやったかといいますと、
feedプラグインで合成したフィードを作成。テンプレートについては後ほど。
フィードのキャッシュ期間ですが、baserCMSのBlogについては更新時にフィードのキャッシュはクリアされるはずなのでとりあえず1日(※2013.7.27追記:公開日時の予約をすると公開時にはキャッシュクリアされないので1時間に変更しました)、外部のスタッフブログについては長くキャッシュされるとまずいので1分にしています。
RSS 2.0 用 のレイアウト作成(ただし、WordPressに合わせて古い項目を追加してます)。
$this->cacheAction = false とすることでサーバーキャッシュは無効化。
テーマ名/layouts/rss2.php
cacheAction = false;
echo "\n";
?>
Lancard.com
http://www.lancard.com/
Lancard.com 新着情報とスタッフブログのRSS(RSS 2.0)
feed(3); ?>
ITEM作成用に作成したfeedのテンプレートはこんな感じ。
テーマ名/feed/rss2item.php
$item): ?>
-
]]>
name; ?>]]>
]]>
]]>
そして固定ページ管理でフィード用のページを作成。
layout = 'rss2'; ?>
以上です。もっといい方法がある気も。
baserCMSで作成したサイトの公開時にルーティングでハマった話
ぶっちゃけ、弊社サイトリニューアルでの話です(baserCMS 2.0.1)。
baserCMSが2系にバージョンアップしたので「まってました!」とサイトをリニューアルしました。
さすがは「コーポレイトサイトにちょうどいい」CMS。作成はサクサクでした。
なのですが公開時に謎のルーティング不具合でハマって「ギニャー!」
どんな症状かといいますと、作成中は表示出来ていたページがなぜか
404 NOT FOUND
Error : The requested address '/recruit' was not found on this server.
app/config/routes.php に直接
Router::connect('/recruit', array('controller' => 'pages', 'action' => 'display', 'recruit'));
と追加すると表示される。どう見てもルーティングがおかしい。
baser/config/routes.php の処理を追っかけてみたりして判明したのはrecruitと渡ってきてほしいurlがrecruit/と末尾に/がついて渡って来ているということ。
公開前までは大丈夫だったのになんでだー?
結論は「apacheのwebrootに旧コンテンツのrecruitディレクトリを残していたためにbaserCMSに渡される前に/をつけられていた」のでした。
.htaccessでbaserCMSに制御をすべて渡すように設定したので、影響でるとは思いもよらず、旧コンテンツを残していたのが不幸の始まり。みなさんもお気をつけください。
ボクはこれで6時間程ハマってました。ネムイヨ。