2011/12/24

Nokogiri 使ったので軽くメモ

Nokogiri を使って HTML のソース解析を簡単にやってみたのでメモ。 まずはインストール。
# これがないと Nokogiri インストール時にエラーになる
$ sudo aptitude install libxml2-dev libxslt1-dev
# Nokogiri をインストール
$ sudo gem install nokogiri
そして、使い方。
require 'rubygems'
require 'open-uri'
require 'nokogiri'

# この open メソッドのために open-uri を require する
html = Nokogiri::HTML(open(url))
# XPath で指定する(css セレクタよりも個人的には XPath の方が好み。)
options = html.search("//div[@id='summary']/select[@class='prefectures']/option")
# 対応する要素がない場合、空が帰ってくる
if options.length.zero?
  puts "データがありません"
else
  options.each do |option|
    # 属性値の取得とテキストの取得
    puts "#{option.attribute('value')} : #{option.text}"
  end
end
DOM がわかってれば簡単だ。 Nokogiri の使い方についてはコチラが簡潔わかりやすいと思う。

2011/08/04

Object#try マジ便利

Rails 2.3 から導入された Object#try これ便利ですね。
とあるオブジェクト obj があって attr という属性を持っている場合、obj.try(:attr) とすると、obj が nil でもエラーがでないと。
# これが
value = obj ? obj.attr : nil

# こんな風にかける
value = obj.try(:attr)

# ほかにもこんなのが
if obj && obj.attr_1 && obj.attr_1.attr_2
  value = obj.attr_1.attr_2.attr3
end

# こうかける
if obj.try(:attr_1).try(:attr_2)
  value = obj.attr_1.attr_2.attr_3
end
nil かどうかを意識しなくてすむというのは非常に大きい。

2011/07/25

Android にモバイル Suica がやってきたよ

7/23 に Android 対応モバイル Suica サービスが開始されたと言うことでさっそくインストールした。
普通にマーケットからするするっとインストール。
寝かせておいた W53CA に SIM を移して、久々に立ち上げて機種変更の手続き。
また IS03 に SIM を入れ替えて移行の手続き。
ちょっとめんどくさかったけど、トラブルなく移行できた。
残ってた 1500 ほどのポイントも生き返った。
後は今使用中のカードタイプの定期券をモバイル Suica に移せるといいんだけど、できるんだっけ?

[2011-07-28_追記]
コールセンターに問い合わせてみたら、機種変更にて引き継いだ場合、別カードの定期情報は取り込めないらしい。
がっかり

2011/06/16

すべての submit に disable_with を

submit ボタンをダブルクリックとかされて、二重登録されてしまうことありますね。
その対策として、クライアント側でお手軽なのが、submit ボタンを押された瞬間に disabled にしてやるというのがあります。
サーバ側でのチェックをするには token を組み込むだのありますが、今回はクライアント側 JavaScript のお話のみということで。

Rails だと非常に簡単にこの機能を提供していて、f.submit :disable_with => '処理中' みたいな感じでできます。
submit_tag でも同様です。(f.submit は submit_tag を呼び出してるし)
ところが、全てのフォームにおいてこれを仕込んでいくのは非常にめんどくさい。
どうせなら一度の設定でアプリケーション全体に適応させましょう。
やってみると意外と簡単で、$RAILS_ROOT/config/initializers の下にこんなコードのファイルを配置するだけ。
module ActionView
  module Helpers
    module FormTagHelper
      alias_method :original_submit_tag, :submit_tag
      def submit_tag(value=nil, options={})
        options[:disable_with] = '処理中...' unless options[:disable_with]
        original_submit_tag(value, options)
      end
    end
  end
end

これで全ての submit は二度押し禁止になりました。
しかし、submit でダウンロードさせた場合、レスポンスがファイルにいってしまうので disabled のまま画面は止まってしまいます。
そんなときは、f.submit :disabl_with => '' のように空文字を渡すだけで大丈夫。

2011/04/27

devise でカスタム認証ロジックを組み込む

たとえば、退職したユーザにはログインさせたくないけど、表示等の関係でユーザ情報を削除できない場合、users テーブルに can_login 列などを作って、フラグ管理しますよね。
んで can_login 列の値でログインを制御したい場合、どう組み込めばいいかなーと悩んでたんですがとりあえずできたのでエントリにしてみます。
devise やコアとなってる warden にそんな機能はありそうなもんだけど、よくわからなかったので自前で仕込みました。
で、認証を行っているメソッドに追加処理をつっこんでやればいいわけです。
devise の lib/devise/controllers/helpers.rb を見ると、authenticate_user! は warden.authenticate! を、current_user は warden.authenticate を呼びだしてる模様。
warden のソースで lib/warden/proxy.rb を見ると、authenticate! も authenticate も _perform_authentication を呼び出しているので、ここで細工してやればよさそう。
んで、最終的には $RAILS_ROOT/config/initializers/extensions/warden_extension.rb を配置して、中身はこんな感じ。
# -*- coding: utf-8 -*-
module Warden
  class Proxy
    alias_method :original_perform_authentication, :_perform_authentication

    private
    def _perform_authentication(*args)
      user, opts = original_perform_authentication(*args)
      # このチェックを入れないとリダイレクトループになる
      unless winning_strategy && winning_strategy.user
        user = nil if user && !user.can_login?
      end
      [user, opts]
    end
  end
end
元メソッド呼び出したあとに、追加でカスタムロジックを追加している。
んで、その内容自体を元メソッドとして上書きってな感じ。
リダイレクトループにさえならなければ、もっとシンプルなソースになったのに、残念だ。

2011/04/10

eclipse galileo にPyDev をインストール

どうせ GAE やるなら Java よりも Python よね。
Java の方が慣れているし、コーディングしやすいんだけど、せっかくの勉強ということで。

というわけで、PyDev を Eclipse にインストールした。
まずは Eclipse を立ち上げて、[ヘルプ] > [新規ソフトウェアのインストール...]

作業対象に http://pydev.org/updates と入力し、[追加]ボタンで PyDev と名づけて [OK] ボタンで保存(上の状態になる)。

上の [Eclipse PyDev] にチェックを入れて [次へ]

インストールの確認なので何もせず [次へ]

ライセンスの確認。同意しますをチェックして [完了]

Now Installing...

証明書の信頼が必要らしい。とりあえず両方共チェックして [OK]

Eclipse の再起動を促されるので再起動。

パースペクティブに PyDev が登録されているから大丈夫だろう。

2011/04/09

Ubuntu 10.04 に Eclipse をインストール

今更ながら Google App Engine で遊ぶために、Eclipse をインストール。
まずは本体をインストール。面倒なので少々古くても apt で入れる。
% sudo aptitude install eclipse

次に日本語化のために、Merge Doc Projectから、Pleiades 本体をダウンロード。
解凍してインストールした Eclipse に上書き。
% unzip pleiades.zip
% cd pleiades
% sudo cp -R features/* /usr/lib/eclipse/features 
% sudo cp -R plugins/* /usr/lib/eclipse/plugins 

eclipse.ini を編集。(sudo が必要)
最後に下記を追加。
-javaagent:/usr/lib/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
(ついでに、-showsplash と org.eclipse.platform をコメントアウトしておけば、起動時の splash を変えられるそうな。)

端末で eclipse -clean とすれば完了。無事に Eclipse が日本語化されました。

2011/03/23

stylesheet_link_tag で media を指定する

Rails3 で作成した画面を印刷すると表示されているように印刷できない。
なんでかなーと調べてみると、デフォルトの stylesheet_link_tag は media="screen" を出力するから、印刷時にスタイルが適応されていない。
media を指定する場合、例えば media="all" で出力したい場合は
<%= stylesheet_link_tag :test, :media => 'all' %>
と指定してやればいいようだ。

2011/02/28

Rails3 で POP 受信したメールを DB に登録する

現在作成しているアプリケーションで、メールを取り込む必要が出てきたので、学習した。
まずは、何も考えず登録するだけのコード。
サンプルでよくある $STDIN.read で取得するデータを POP3 で取得するにはどうすればいいかだけがカギかな。
class MailClient
  Net::POP3.start('mail_server', 110, 'account', 'password') do |pop|
    pop.mails.each |m|
      UserMailer.receive(m.pop)
      m.delete
    end
  end
end

ところが今回の環境では、サーバからメールを削除できないという条件があった。
(正確には別の手段で10日以上たったメールを削除している)
このため、差分受信を自前で実装しなければならない。
すでに受信したメールを判別するには、一意なキーが必要だけど候補は二つ。
Net::POPMail#unique_id か Mail#message_id でも、Mail オブジェクトを作るためには、m.pop でメールを受信しなければならない。(pop を呼び出す前までは、LIST コマンドで取得した数値だけ持っている)
というわけで、Net::POPMail#unique_id で判別したい。すなわち、unique_id を DB に登録した、
しかし、ActionMailer#receive メソッドで自動的に Mail オブジェクトにパースされると、この unique_id の値がどっかに行くようだ。
なので、引数が一つしか渡せない ActionMailer#receive では unique_id を DB に登録するのは無理だ。
というわけで、ActionMailer#receive を使うのは諦めるしかない。
結局、下記のようなコードになった。

class MailClient
  Net::POP3.start('mail_server', 110, 'account', 'password') do |pop|
    registered_unique_id_list = UserMail.select(:unique_id).all.collect { |um| um.unique_id }
    pop.mails.each |m|
      unless registered_unique_id_list.include?(m.unique_id)
        mail = Mail.new(m.pop)
        save_mail(mail, m.unique_id)
      end
    end
  end
end
とりあえずは、これで動いている。
でも、そもそも差分受信のロジックを要勉強な気がする。
どっかのメーラのソースでも読むべきかな

2011/02/16

gem をアップデートしたら redmine の表示がおかしくなった

既存サーバに新しく rails アプリを登録したときに、最新環境にしたら redmine の表示がおかしくなった。
rails のバージョンは freeze されているけど、I18n なんかはシステムの gem を利用しているので、その影響だろう。
こんな風に、I18n の変数展開がうまくいっていない。
対応自体は簡単で、RAILS_ROOT/config/locals/ja.yml のリプレースホルダの形式を変更すればいい。
{{count}} のような旧形式で定義されているので、これを %{count} の形式に変更する。
あとは passenger なり、apache なりを再起動すればok。
要するに以前の形式のサポートが打ち切られたわけですね。

2011/02/15

rails3 で div.field_with_errors を抑制する

div で囲んでくれるため、デザイン的に結構邪魔な Rails の field_with_errors。
これを出力しないには application.rb に一行足すのが一番簡単っぽい。
config.action_view.field_error_proc = proc { |input, instance| input }

2011/02/03

IS03にEdyがやってきた

Edyがスマートフォンに対応しました

ということでようやく Edy が IS03 で使えるようになったようです。
さっそくインストールしてみましょう。

スマートフォンでEdyを利用するを参考に進めてみましょう。
まあ、ココにアクセスして指示通りに行うだけですけど。
ちなみにアプリケーションの[おサイフケータイ]→[サービス紹介サイト]からもいけます。
ただ、デフォルトブラウザじゃないとできなかった。Opera や Dolphin Browser じゃプラグインの関係なのか登録までこぎ着けることができなかった。
Opera だとスマートフォン用サイトすら表示されなかったし。

必要事項を入力して登録は完了したけど、まだ利用できない。
チャージしようと思ったけど、クレジットカードは登録に二日ほどかかるということでチャージできない。
あとでコンビニからチャージしてみましょう。

で、実はここで終わりじゃなくて・・・
再びアプリケーションから[おサイフケータイ]を選ぶと[電子マネー「Edy」]という項目が増えています。
タップすると Edy のアプリケーションダウンロード画面に遷移します。
ちゃんと専用アプリも用意されているんですね。
まあ、チャージなどはアプリから仕様としても結局ブラウザ経由のようですけど。

ともあれ、これで一つ便利になった。あとは Suica だ

2011/01/11

fancybox のバグが直っていた

これまで fancybox の 1.3.1 を利用していたが、内部のテキストボックスやテキストエリアでカーソルキーによる左右移動ができなかった。
fancybox を最新(1.3.4)にアップデートしたら直った。
changelog を見ると、1.3.2 で直ってたのかな。
見逃していた。

2011/01/04

Devise でタイムアウトまでの時間を変更する

現在のシステムでは Devise を認証システムとしているのですが、タイムアウト時間がデフォルトで 30 分となっています。
タイムアウト時間の確認はこんな感じでできます。(User は generate したモデル名により変わる)
% rails c
irb(main):001:0 => User.timeout_in
=> 1800 secondes
User.timeout_in が使用されているのは、ここでわかる。
というわけで、User.timeout_in を上書きしてやればうまくいきそうだが、ちょっとかっこわるい。
やっぱり、application.rb や production.rb なんかで config.hogehoge でやりたい。
調べてみたらこんな感じでできるようだ。(とりあえず2時間に変更する)
module App
  class Application < Rails::Application
    # some settings

    # devise settings
    config.devise.timeout_in = 2 * 60 * 60 # timeout seconds

    # some settings
  end
end
確認してみる。
% rails c
irb(main):001:0 => User.timeout_in
=> 7200
うん変わってる。(secondsがどっか行ったが)
config.devise の実体は Devise モジュールで、ソースを見るとその他にも多くの設定が行えるのがわかる。
devise 関連の設定は config.devise で行うと把握しておけば大丈夫だろう。

-- 2011-01-28 追記
# このほうがいいね
# config.devise.timeout_in = 2 * 60 * 60
config.devise.timeout_in = 2.hours

あけましておめでとうございます

年末は尻すぼみになってしまっていたこの blog
今年も不定期ながら更新していく予定です。
ネタは相変わらず Rails3 ネタがメインかなと。
IS03 を早々に入手しているのでそのうち andoroid ネタや IS03 ネタもやりたいです。
PHP を学習せねばならん状況になっているので、そちらも何か書くかもしれません。

ともかく、今年もよろしくお願いいたします。