2012/06/29

[rails] ストアドファンクションをロードするrakeタスク

Railsアプリの開発環境下でMySQLのストアドファンクションを作成し、 rakeでロードできるようにしています。
おおよそ次の手順で実現しました。

ストアドファンクションを書く。

{Rails.root}/script/db/sql 配下に、拡張子sqlのファイルとして、 ストアドファンクションを作成。

rakeタスクを書く。

{Rails.root}/lib/task 配下に、db_functions.rakeを作成。
タスクは、

  • db:functions
  • db:functions:load
の2つ。
1つ目は、ロードするファンクションの一覧を表示するタスク。
2つ目は、実際にファンクションをロードするタスク。
内容は以下の通り。
namespace :db do
  namespace :functions do
    desc "List .sql files."
    task :list => :environment do
      path = Rails.root + "script/db/sql/*.sql"
      Dir.glob(path) do |sql|
        puts File.basename(sql)
      end
    end

    desc "Load stored functions to the database."
    task :load => :environment do
      begin
        cmd = build_load_cmd(ActiveRecord::Base.configurations)
        path = Rails.root + "script/db/sql/*.sql"
        Dir.glob(path) do |file|
          exec(cmd + " < " + file)
        end
      rescue => e
        puts e.message
        raise e
      end
    end
  end
end

def build_load_cmd(db_config)
  env = ENV['RAILS_ENV']
  env = 'development' if env.nil?

  conf = db_config[env]
  cmd = "mysql"
  cmd << " -h " + conf["host"]     if conf["host"]
  cmd << " -u " + conf["username"] if conf["username"]
  cmd << " -p"  + conf["password"] if conf["password"]
  cmd << " "    + conf["database"]
  cmd
end

これで、rake db:functions:load とすると、ファンクションが生成されます。
もちろん、sqlファイル内で、drop functionしてからcreate functionしています。

デプロイにCapistranoを使う場合、deploy:migrateタスクのafterフックにdb:functions:loadを追加すれば、 DBに変更がある場合に、ファンクションの更新も漏れ無く実行されます。

2012/06/17

[rails] Rails3でWebフォントを使う。

Webフォントは、サーバーサイドにフォントを配置し、サーバーサイドが指定したフォントを クライアントに使用させる仕組みです。
Rails3で、Webフォントを使用する場合の手順を書きます。
(本当にこれでいいのか自信がありませんが、それらしく動きました。)

  1. まず、フォントファイルを配置するディレクトリを作り、フォントファイルを配置します。
    僕は、{Rails.root}/app/assets/fonts というディレクトリを作りました。
    フォントファイルは、ttf形式のみです。(IEのこととかはここでは考えず。)
  2. CSSにフォントを定義します。
    まず、@font-faceの定義。(下はSCSSの記載です。)
    @font-face{
      font: {
        family: 'migmix-1p';
        weight: 'normal,bold';
        style:  'normal';
      }
      src: asset-url('migmix-1p-regular.ttf', font) format('truetype'),
           asset-url('migmix-1p-bold.ttf', font)    format('truetype');
    }
    
    asset-urlは、Rails3のassets pipelineで、assetに対するパスを解決してくれるヘルパです。
    次に、@font-faceの適用。
    全てのコンテンツにWebフォントを使用したかったので、body要素に上記フォントを指定。
    body {
      :
      font-family: 'migmix-1p';
      :
    }
    
  3. 最後に、application.rbを編集し、assetsパスにfontsを追加します。
    config/application.rbに、以下の設定を追加します。
    config.assets.paths << "#{Rails.root}/app/assets/fonts"
    
  4. Webフォントが適用されていることを確認します。

Rails3でWebフォントを利用する方法について書きました。
より適切な方法をご存じの方がいらしたら、コメントいただけると嬉しいです!

2012/06/14

[rails] jpmobileでスマートフォンページ振り分け

jpmobileを使うと、簡単に携帯向けページを作れる、 とのことで、スマートフォン向けのページをRails3で作った。

以下のサイトを参考にした。
今最もモテる組み合わせのRails3.1 + jp_mobile でサイトを作った際のメモ

要件としては、

  • PC向けページとスマートフォン向けを同じURLで
  • キャリアなどは細かく判定せず
  • Railsだけで振り分ける
というもの。
HTTPサーバによるUserAgentの判定などはしない。

手順は簡単。

  1. 普通に(PC向けに)MVCを実装する。
  2. Gemfileにjpmobileを追加。
    ※ Railsのバージョンとjpmobileのバージョンの対応に注意。 僕はRails3.1系を使っているので、jpmobileは2.0.8を使用。
    gem 'jpmobile', '2.0.8'
    
  3. スマートフォン用のリソースを作成(view,css,js)。
    スマートフォン用のリソースを、それぞれ、
    • {Rails.root}/app/views/layouts/application_smart_phone.html.erb
    • {Rails.root}/app/views/xxxxxxx/xxxxx_smart_phone.html.erb
    • {Rails.root}/app/views/xxxxxxx/smart_phone/xxxxx.html.erb
    • {Rails.root}/app/assets/stylesheets/smart_phone/application.css.scss
    • {Rails.root}/app/assets/stylesheets/smart_phone/xxxxx.css
    • {Rails.root}/app/assets/javascripts/smart_phone/application.js
    • {Rails.root}/app/assets/javascripts/smart_phone/xxxxx.js.coffee
    のように作成し、配置した。cssのインクルードや、jsのインクルードは、きちんと整理して実装する。
    jpmobileには、ViewSelectorという機能があり、内部でUserAgentを判定し、 しかるべきビューに振り分けてくれる。
    コレを使うには、コントローラに、
      include Jpmobile::ViewSelector
    
    を書く。
    僕は、ApplicationControllerに実装した。
    としておいて、例えばiPhoneからアクセスした場合、jpmobileがビューを、
    • xxxxx_smart_phone_iphone.html.erb
    • xxxxx_smart_phone.html.erb
    • xxxxx.html.erb
    の順で、範囲の狭い順に検索し、見つけたものをレンダリングしてくれる。
    ※ xxxxxは、action名。
    iPhoneかAndroidか、みたいな判定をしなくていい場合は、xxxxx_smart_phone.html.erbを用意すればいい。
  4. 最後に、asset:compileの対象に、stylesheets/smart_phoneとjavascripts/smart_phoneを追加する。
    {Rails.root}/config/environments/production.rbに、
    initializer :after_append_asset_paths,
    :group => :all,
    :after => :append_assets_path do
      config.assets.paths << Rails.root.join('app', 'assets', 'stylesheets', 'smart_phone')
      config.assets.paths << Rails.root.join('app', 'assets', 'javascripts', 'smart_phone')
    end
    
    を追記して、smart_phone配下のリソースをコンパイル対象に含める。

上記で、一応ビューの切り替えが実現できた。
Androidでアクセスしたらば、スマートフォン用ページが表示されました。

2012/06/01

[rails] htmlテンプレートをレンダリングしてjs.erb内で使用する。

Rails3のlink_toや、form_for、form_tagで:remote => trueを指定すると、 デフォルトでdataType=jsでリクエストが発行される。
この場合、コントローラは、jsとして応答したいが、jsでページの一部のコンテンツを更新したい時、 更新内容は、html.erbとして定義しておきたい、という場合がある。
js.erbの中で、html.erbをレンダリングした結果を使用するには、
  $("some_element").html("<%= escape_javascript(render(:partial => 'some_partial_html')) %>");
のように、escape_javascriptヘルパを利用する。