migrationファイルにPROCEDUREを書く方法(Rails3)

Rails+MySQLな環境で、日時処理なんかでカラムの値を集計する場合、簡単な集計処理ならバッチを書かずにプロシージャに任せて、イベントスケジューラ実行、なんてことがあると思います。

Railsで開発してるとプロシージャもmigrationファイルに書く必要があると思うんですが、その備忘録

def up
execute "CREATE PROCEDURE hogehoge_summary()
    BEGIN
        プロシージャ本文
    END"
end

def down
    execute "DROP PROCEDURE IF EXISTS hogehoge_summary"
end

別に気を付ける部分もないと思うんですが、migrationのなかではデリミタ指定が使えないのと、そのせいでcreateとdrop if existsが一緒に書けないのでupとdownでわけないとダメでした。

うーん、rubyアイドルと恋に落ちたい。

register_prefilter再び

どうも、僕です。

こんな僻地のブログでもGoogleさんがインデックスしてくれているお陰で、わざわざ足を運んでくださる方がいらっしゃるようで、大変有難いことです。

ところでこのブログ、どうせみんなTOKYO-TUBEの動画を保存してオフラインで鑑賞する方法が目的で訪問してくるんだろうと思ってたら、意外とSmartyのエラーで来てくれる人がいることがわかったので、register_prefilterについて追記したいと思います。

以前のエントリでは、外人のQA引っ張ってきて、黙ってregisterFilter使えよ的な回答をしたわけですが、もうちょっと具体的に書きたいと思います。


たとえばSmary2系でSmartyクラスを独自にextendしてregister_prefilterを使う場合、こんなふうに書きますね。

class SmartyExtends extends Smarty{ ←Smartyクラスを継承

    public function __construct(){ ←コンストラクタにプレフィルタを登録

        // prefiliter
        parent::register_prefilter( 'default_display_filter' ); ←前処理

        function default_display_filter( $tpl_src, &$Smarty ){ ←前処理の中身
        
            ----- 何か適当な処理 ---
            
            return $tpl_src;
        }
    }
}

まず先頭の

class SmartyExtends extends Smarty

で、SmartyをextendしたSmartyExtendsを作ります。
プログラムからnewするのはSmartyではなく、SmartyExtendsになります。

で、

function __construct(){ ... }

内にparent::register_prefilterすることで、SmartyExtendsがnewされた時点でdefault_display_filterが呼び出されるわけです。

newする度に呼び出されるのは効率的じゃなくね?っていう話もありますので、そういうのが気になる人はdisplayの中でもどこでも好きな様にやってもらって構いません。

さて、これをSmary3でやると、下記のNoticeが出ます

Notice: function call 'register_prefilter' is unknown or deprecated.


これを回避するためには、registerFilterを使うわけですが、こんな風に書き換えます。

class SmartyExtends extends Smarty{    ←Smartyクラスを拡張するのは一緒

    //テンプレート前処理
    function registerFilter($tpl_src, $type='pre'){    ←明示的に前処理を指定
        
        parent::registerFilter( $type,array('SmartyExtends','default_display_filter'));    ←前処理したい関数を登録

    }
    
    static function default_display_filter($tpl_src,$sobj){    ←実際の前処理を記述

         ----- 何か適当な処理 ---

        return $tpl_src;
    }
    
    function display($tempfile='',$cache_id = null, $compile_id = null, $parent = null){    ←display文の中でフィルタを呼ぶように変更
    
        $this->registerFilter($tempfile);    ←parent::displayする前に前処理を明示的に呼び出す
        
        parent::display($templatepath,$cache_id,$compile_id,$parent);    ←display
    }
}


先頭のextendは一緒ですが、Smarty3ではコンストラクタで処理しようとするとなぜかエラーになリます。

コンストラクタはやめて、今回はdisplay内で呼び出すことにします。

function display($tempfile='',$cache_id = null, $compile_id = null, $parent = null)

新たにdisplayクラスを作って、親のdisplayを呼び出すってやつなんですが、PHP5.3からはオーバーライドするときに
上書き元のclassと変数の数が一致しないとエラーを返すので、合わせてやる必要があります。

displayの中でプリフィルタを呼び出すわけですが、ExtendしたSmartyクラス内でカスタムしたregisterFilterを呼び出すように書き換えます。

$this->registerFilter($tempfile);

なんでこんな処理をする必要があるのかというと、後続の処理でプレフィルタにテンプレートを引き渡すためだそうです。
Smartyのサイトに書いてあったとおりです。ここで疑問を挟んではいけません。

    function registerFilter($tpl_src, $type='pre'){
        parent::registerFilter( $type,array('SmartyExtends','default_display_filter'));    
    }

はparent::registerFilterを呼び出すためだけのメソッドですが、直接parent::registerFilterを呼び出すとテンプレート$tpl_srcがプレフィルタに渡せないので、こんなふうに書きます。
Smartyのサイトに書いてあったとおりです。疑問を挟んではいけません。

$typeに指定できるのは、Smartyによれば

"pre", "post", "output" and "variable"

なので、呼び出すタイミングによって$typeを変えます。今回はpreを使いました。

もう一個の引数

array('SmartyExtends','default_display_filter')

SmartyExtendsが以前の&$SmartyにあたるSmartyオブジェクトで、default_display_filterが、プリフィルタしたい処理です。

default_display_filterの第一引数はテンプレート変数で、第二引数はSmartyオブジェクトが入ってます。

static function default_display_filter($tpl_src,$sobj){

第一引数には$this->registerFilter()したときの$tempfileがそのまま渡ってきてます。
第二引数を書いておけば、勝手にSmartyオブジェクトが入ってくれるので、フィルタ内でSmartyメソッドが呼び出せるはず。

たぶんこれでSmarty3でもプリフィルタが使えるはず・・・!

Rails+MongoでSexy Validationする方法

こんにちは。

最近社内ニートですることないのでRails+Mongoやってます。

Railsとか言ってるけどもともとPHPしかできないゆとりなんで、まず最初のRails+MySQLで色々つまづいたりもしてますが、私は元気です。

PHPer(しかも独自FW派)がRailsに惚れ込むまでのエントリを書きたいところですが、大長編になりそうなので今回はあんまり日本語のヘルプに引っかからなかったMongoでSexy Validationやる件についてはまりどころを書きます。

Rails3からSexy Validationが導入され、モデルに

validates :userid, :presence => true

みたいのを書けばバリデーションしてくれるようになりました。



なんて偉そうなこと書いてますが、そもそもRails2を知らないので、「一行書き足すだけでチェックしてくれるなんて超便利!」と素直に感動してますごめんなさい。

で、これを日本語化するには
https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml
をlocales/にぶち込めばいいっていうのが常識ですが、これだとフィールド名が日本語名にならないので別途ja.ymlで


  activerecord:
    attributes:
      hogehoge:
        userid: ユーザーアイディー

とかやります。


でもmongo_mapperはActiveRecordを使わないのでこれが使えません。
なのでまず使いたいモデルでValidationsが使えるよう、ActiveModel::alidationsをextendします。
たとえば今回はhogehogeモデルなので、モデルの先頭にこんな感じで追記します。


class Hogehoge
  include MongoMapper::Document
  extend ActiveModel::Validations ←追記した

  validates :userid, :presence => true ←Validation項目

  key :userid, String ←Mongoのドキュメント項目
end

次にlocale/ja.ymlのactiverecordの部分をmongo_mapperに書き換えます。(別にja.ymlじゃなくてもいい)


  mongo_mapper:
    attributes:
      hogehoge:
        userid: ユーザーアイディー

ほら、ちゃんと動いた!(画像略)

Rails+Mongoはあんまり日本語のヘルプがなくて困りますが、時間が余ってる時は英語のサイトを探しまくるのも楽しいです。

今回はstackoverflowの下のページを参考にしました。
http://stackoverflow.com/questions/3465481/whats-the-way-to-translate-model-attributes-in-rails-with-mongoid

これによればmongoid:で動いたよ!って言ってますがmongoidっていうgemがあるんですかね?


ゆとりだからわかんないや(^q^)



以上よろしくお願いいたします。

puppet-2.7.5のインストールで躓いた件

新しくpuppetサーバを立てようと思い立ったが、ソースからインストールするのも面倒なので、yumを使うことにした。

そこら辺のブログで出てる通り、まず、puppetのリポジトリを追加

# vi /etc/yum.repos.d/dag.repo
[dag]
name=DAG RPM Repository
baseurl=http://ftp.riken.jp/Linux/dag/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
gpgkey=http://ftp.riken.go.jp/pub/Linux/dag/RPM-GPG-KEY.dag.txt

yum install実行

yum install puppet-server


すると。。。


Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.oss.eznetsols.org
* extras: ftp.oss.eznetsols.org
* updates: centos.vr-zone.com
Setting up Install Process
Resolving Dependencies

    • > Running transaction check
      • > Package puppet-server.noarch 0:2.7.5-1.el5.rf set to be updated
    • > Processing Dependency: puppet = 2.7.5-1.el5.rf for package: puppet-server
    • > Running transaction check
      • > Package puppet.noarch 0:2.7.5-1.el5.rf set to be updated
    • > Processing Dependency: facter >= 1.5 for package: puppet
    • > Processing Dependency: ruby-shadow for package: puppet
    • > Processing Dependency: ruby-augeas for package: puppet
    • > Processing Dependency: libselinux-ruby for package: puppet
    • > Running transaction check
      • > Package facter.noarch 0:1.6.2-1.el5.rf set to be updated
      • > Package libselinux-ruby.i386 0:1.33.4-5.7.el5 set to be updated
      • > Package puppet.noarch 0:2.7.5-1.el5.rf set to be updated
    • > Processing Dependency: ruby-augeas for package: puppet
      • > Package ruby-shadow.i386 0:1.4.1-2.el5.rf set to be updated
    • > Finished Dependency Resolution

puppet-2.7.5-1.el5.rf.noarch from dag has depsolving problems
--> Missing Dependency: ruby-augeas is needed by package puppet-2.7.5-1.el5.rf.noarch (dag)
Error: Missing Dependency: ruby-augeas is needed by package puppet-2.7.5-1.el5.rf.noarch (dag)
You could try using --skip-broken to work around the problem
You could try running: package-cleanup --problems
package-cleanup --dupes
rpm -Va --nofiles --nodigest
The program package-cleanup is found in the yum-utils package.



うーん。。。
バージョンが上がってるせいか、依存関係エラーが起きる。

とりあえずrubyのバージョンを確認すると

ruby -v
ruby 1.8.5 (2006-08-25) [i386-linux]


若干古かったので、yum erase してソースコードからpuppetを入れてみたのだが、これをクライアント・サーバ全部でやる気はさすがに起きない。


ということで、もう一度インストールしなおし、まずエラーとなってる箇所


Missing Dependency: ruby-augeas is needed by package puppet-2.7.5-1.el5.rf.noarch (dag)

を潰すことにした。


まず先にrubyだけインストール

# yum install ruby


ruby-augeasが使うのでaugeas-libsをインストール

# yum install augeas-libs


ruby-augeasをrpmでインストール

# wget ftp://fr2.rpmfind.net/linux/epel/5/i386/ruby-augeas-0.4.1-1.el5.i386.rpm
# rpm -ivh ruby-augeas-0.4.1-1.el5.i386.rpm


再度puppetをインストール

# yum install puppet-server
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.oss.eznetsols.org
* extras: ftp.oss.eznetsols.org
* updates: centos.vr-zone.com
extras | 2.1 kB 00:00
updates | 1.9 kB 00:00
Setting up Install Process
Resolving Dependencies

    • > Running transaction check
      • > Package puppet-server.noarch 0:2.7.5-1.el5.rf set to be updated
    • > Processing Dependency: puppet = 2.7.5-1.el5.rf for package: puppet-server
    • > Running transaction check
      • > Package puppet.noarch 0:2.7.5-1.el5.rf set to be updated
    • > Processing Dependency: facter >= 1.5 for package: puppet
    • > Processing Dependency: ruby-shadow for package: puppet
    • > Processing Dependency: libselinux-ruby for package: puppet
    • > Running transaction check
      • > Package facter.noarch 0:1.6.2-1.el5.rf set to be updated
      • > Package libselinux-ruby.i386 0:1.33.4-5.7.el5 set to be updated
      • > Package ruby-shadow.i386 0:1.4.1-2.el5.rf set to be updated
    • > Finished Dependency Resolution

Dependencies Resolved

================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
puppet-server noarch 2.7.5-1.el5.rf dag 14 k
Installing for dependencies:
facter noarch 1.6.2-1.el5.rf dag 64 k
libselinux-ruby i386 1.33.4-5.7.el5 base 60 k
puppet noarch 2.7.5-1.el5.rf dag 1.0 M
ruby-shadow i386 1.4.1-2.el5.rf dag 14 k

Transaction Summary
================================================================================
Install 5 Package(s)
Upgrade 0 Package(s)

Total download size: 1.1 M
Is this ok [y/N]: y
Downloading Packages:
(1/5): puppet-server-2.7.5-1.el5.rf.noarch.rpm | 14 kB 00:00
(2/5): ruby-shadow-1.4.1-2.el5.rf.i386.rpm | 14 kB 00:00
(3/5): libselinux-ruby-1.33.4-5.7.el5.i386.rpm | 60 kB 00:00
(4/5): facter-1.6.2-1.el5.rf.noarch.rpm | 64 kB 00:00
(5/5): puppet-2.7.5-1.el5.rf.noarch.rpm | 1.0 MB 00:00
--------------------------------------------------------------------------------
Total 291 kB/s | 1.1 MB 00:03
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
Installing : libselinux-ruby 1/5
Installing : ruby-shadow 2/5
Installing : facter 3/5
Installing : puppet 4/5
Installing : puppet-server 5/5

Installed:
puppet-server.noarch 0:2.7.5-1.el5.rf

Dependency Installed:
facter.noarch 0:1.6.2-1.el5.rf libselinux-ruby.i386 0:1.33.4-5.7.el5
puppet.noarch 0:2.7.5-1.el5.rf ruby-shadow.i386 0:1.4.1-2.el5.rf

Complete!

無事にインストールできましたよ、と。。。



ちなみに新しいバージョンでは、--verboseだけではフォアグラウンドにならないので、デバッグ目的でフォアグラウンド起動する際は--no-daemonizeオプションを付けて起動する必要があります。

# puppetmasterd --verbose --no-daemonize

【iPhone】脱獄した黒SIMってみんなどうしてんの?

最近Titanium StudioをただのAptinaとしてしか使ってない僕です。

前に会社から社用のREGZA Phoneなるものを借り受けたんですが、個人用のiPhoneと合わせてスマホ2台持ち歩きたくないんで、ほとんど使ってませんでした。

それじゃさすがにもったいないし、最近の禿よしさんの電力権益ゲットのなりふり構わない具合に不快感を覚えたので、もうiPhone 3GSを脱獄しちゃおう!って思い立って脱獄しました。

脱獄自体はredsn0wとかpwangetoolでさくっとできちゃうんですが、自分の使ってるiPhoneのベースバンドが06.15.01より上だと脱獄したあとにSIMフリー化できないので、「install custom bundle」にチェックを入れないと駄目です。
20110719.gif

custom bundleはiPad用のベースバンドなので、06.15.00にダウングレードされます。人によってはここでGPSが使えなくなったりしますが、とりあえず自分は大丈夫でした。

最初に脱獄した時、コレにチェックを入れなかったのでSIMフリーにならず、再度脱獄する羽目になりました。
ちなみに脱獄自体は何度でもできます。

で、脱獄したdocomoのSIMを挿すんですが、mopera-Uに入ってないとデータ通信が使えません。
このmopera-Uってのが結構くせ者で、DoCoMoのスマホだと上限5700円のハイスピード回線が使えるんですが、それ以外だと、
速度が速い方:372円(税込390円)〜13,000円(税込13,650円
128K固定の方:5,700円(税込5,985円)
というふうに回線によって価格が変わります。
今回は社用端末なんで、請求書の金額が急に上がると怒られるので128Kしか怖くて使えませんでした。
ていうか何この差別。

ここまで設定すると晴れてdocomo SIMでiPhoneが使えるようになります。
ただし当然softbank.ne.jpは受信出来なくなります。
困る人はそもそも脱獄なんてしないでください。

i.softbank.jpは送受信できるので、こっちが使えりゃ問題ないって人は脱獄してみてもいいんじゃないかな。
※だってただの電子メールアカウントだもの。黒SIM解約しなければ使えて当然
ただ、これも困った事になぜか絵文字が相互変換されなくなります。
ゲートウェイが変わるから仕方ないみたいな記事書いてる奴もいるけど、i.softbank.jpって電子メールだし別にGW関係なくね。
何でMMSじゃないのに絵文字変換フィルタを通らないのか謎。

でまあ、ここまでがiPhoneの脱獄で、あとは黒SIMの番号に電話がかかってきたときに出られないとまずいので、黒SIMを有効活用する必要があります。

禿仕様の黒SIMはソフトバンク端末に挿しても認識しないのは有名な話ですが、実はVodafone時代の端末であれば普通に使える事はあまり知られていません。

しかも同じVodafoneでも国内産は通話はOKだけどMMSは無理、海外端末だとどっちもOKという謎仕様なので、ヤフオクで捨て値で売ってる702NKあたりを買えば普通に使えます。

ただ、今回無駄にでかいスマホ2台持つのが嫌だったのにさらにでかいVodafone端末持つくらいなら別に脱獄しなくても良くねなんていう本末転倒な事態は避けたかったので、手持ちのSIMロック解除したNM706iを使う事にしました。

SIMフリー版Nokia携帯に黒SIMを挿すと
20110719
ちゃんと認識した!

しかし通話はできるものの予想通りネットやMMS、電子メールは使用出来ませんでした。意味ねーーー。
オクでSC804SSでも買うかなあ。。。



というわけで、今回の検証結果
・脱獄してdocomoの回線を使うと高くなる
・黒SIM再利用は海外端末必須


ちなみにiPhoneでよく見るyou gat mail画面、実はあれ、プッシュ専用番号がSMSで飛ばしてるのを端末が受信すると表示されます。
なのでSIMフリー化して別の端末に黒SIM挿すと、黒SIM側→you gat mail受信、SIMフリー側→本文受信という素敵な現象が発生します。だから何だ。

register_prefilterの挙動を変えるとかなしにしようぜSmartyさん

Smartyにはプリフィルタ機能ってやつがあって、それぞれテンプレートのコンパイル前に下記の挙動を行うっていうのはよく知られた話。


register_prefilter()・・・プレフィルタを実行
register_postfilter()・・・ポストフィルタを実行
register_outputfilter()・・・アウトプットフィルタを実行

Smartyを使うPHPユーザーは、だいたいこれを使ってテンプレートを出力する際に共通ヘッダ、フッタなんかを出したりしてると思います。



で、最近Smarty3を使って例のごとくプレフィルタを実行しようとしたら、エラー

Notice: function call 'register_prefilter' is unknown or deprecated.

Smartyのバージョンなんてしばらく上げてなかったので、焦ってググると同じような症状に悩んでる人を見つけた。


ドキュメント読めよカスとでも言いたげなリンク一文が貼ってあるのでクリックすると。。。。


...orz

Name

registerFilter() — dynamically register filters
Description
void registerFilter(string type,
mixed callback);

Use this to dynamically register filters to operate on a templates. It uses the following parameters:

type defines the type of the filter. Valid values are "pre", "post", "output" and "variable".

callback defines the PHP callback. it can be either:

A string containing the function name

An array of the form array(&$object, $method) with &$object being a reference to an object and $method being a string containing the method-name

An array of the form array($class, $method) with $class being the class name and $method being a method of the class.

とりあえずregisterFilter()を使えよ、と。
変なクラス使うなよと。

ていうかこのクラス、いつから使えるようになってたの。。。
もしかして_prefilterを使うのがイレギュラーだったの。。。。

にしてもリンクくらい貼っておいてよSmartyさん!ヽ(`Д´)ノ ウワァァァン

次回に続く。