Archive for category ruby

Google adwords APIのKeywordTool#getKeywordVariationsが遅い人へ

Posted by admin on Wednesday, 13 January, 2010

V200909のTargetingIdea#getを使うと速くなりますよ!

adwords4rを利用したサンプルコード。

    service = @adwords.service("TargetingIdea", 200909)

    kw = service.module::Keyword.new
    kw.text = keyword
    kw.matchType = "BROAD"

    parameter1 = service.module::RelatedToKeywordSearchParameter.new
    parameter1.keywords = [kw]

    parameter2 = service.module::AverageTargetedMonthlySearchesSearchParameter.new
    parameter2.operation = service.module::LongComparisonOperation.new
    parameter2.operation.minimum = 0
    parameter2.operation.maximum = 100_000_000_000

    selector = service.module::TargetingIdeaSelector.new
    selector.searchParameters = [parameter1, parameter2]
    selector.requestedAttributeTypes = ["AVERAGE_TARGETED_MONTHLY_SEARCHES"]
    selector.ideaType = "KEYWORD"
    selector.requestType = "STATS"
    selector.localeCode = "ja_JP"
    selector.currencyCode = "JPY"
    selector.paging = service.module::Paging.new
    selector.paging.startIndex = 0
    selector.paging.numberResults = 1
    service.get(selector)

このサンプルでは月の平均検索ボリューム(AVERAGE_TARGETED_MONTHLY_SEARCHES)を1件のみ取得となっています。もしかすると自分の探し方が悪かったかもしれませんが、KeywordTool#getKeywordVariationsでは1件のみの取得が出来ませんでした。

V200909のTargetingIdea#getを使うと細かい設定ができるため、性能を良く出来ます。体感で70%ぐらい速くなりました。

HpricotのXPATHを使って属性名の小文字大文字を無視する

Posted by admin on Tuesday, 5 January, 2010

HpricotのXPATHではlower-caseとupper-caseは使えなかったんですね。アイター。

ということでさっくりとコードいじりました。

例えばmetaタグのdescriptionを取り出すときに、以下のように大文字になっていると

<meta NAME="DESCRIPTION" ...>

次のようなxpathでは取り出せません。

//head/meta[@name=description]

これを解決するには以下のようにxpathの関数を使うのが理想なのですが

//head/meta[lower-case(@name)=description]

Hpricotでの実現方法が分からなかったのでElem::Travを直でいじるという乱暴な方法で解決しました。

#
# 属性へのアクセスは全て小文字に揃えます。
#
module Hpricot
  module Elem::Trav
    def has_attribute?(name)
      self.raw_attributes && self.raw_attributes.has_key?(name.to_s.downcase)
    end
    def get_attribute(name)
      a = self.raw_attributes && self.raw_attributes[name.to_s.downcase]
      a = Hpricot.uxs(a) if a
      a = a.downcase if (a && self.name.downcase == "meta" && name == "name")
      a
    end
    alias_method :[], :get_attribute
    def set_attribute(name, val)
      altered!
      self.raw_attributes ||= {}
      self.raw_attributes[name.to_s.downcase] = val.fast_xs
    end
    alias_method :[]=, :set_attribute
    def remove_attribute(name)
      name = name.to_s.downcase
      if has_attribute? name
        altered!
        self.raw_attributes.delete(name)
      end
    end
  end
end

これでmetaタグのname属性だけが全て小文字に揃います。

exception_notificationをdevelopmentでエラーメール投げつつ、元のエラー画面を出す方法

Posted by admin on Monday, 5 October, 2009

エラー画面を出しつつ、エラーメールが欲しいシーンって結構ありますよね。エラー履歴を検索したい時などなど。

そんな時にはexception_notifiableを拡張してあげます。

具体的には、vendor/plugins/exception_notification/lib/exception_notifiable.rb の rescue_action_in_public(exception)メソッドの下辺りにrescue_action_locallyを追加します。

以下ソースコードです。

    def rescue_action_locally(exception)

      deliverer = self.class.exception_data
      data = case deliverer
        when nil then {}
        when Symbol then send(deliverer)
        when Proc then deliverer.call(self)
      end

      ExceptionNotifier.deliver_exception_notification(exception, self, request, data)

      super(exception)

    end

後の使い方は同じです。

コントローラーはこうで。

class ApplicationController < ActionController::Base
  include ExceptionNotifiable
end

config/enviroment.rbはこうです。

Rails::Initializer.run do |config|
...省略...
  config.action_mailer.smtp_settings = {
    :address   => "xxxx",
    :domain    => "xxxx",
    :user_name => "xxxx",
    :password  => "xxxx",
    :authentication => :login,
  }
end
ExceptionNotifier.exception_recipients = "hoge@hoge"
ExceptionNotifier.sender_address = %("Error" )
ExceptionNotifier.email_prefix = "[Error]"

railsはこういうのシンプルに出来るからいいですね。

Eclipseでさくっとrubyのソースコードを編集したい(RDTだけ入れたい)

Posted by admin on Friday, 18 September, 2009

この内容はEclipse3.4で行っています。

Eclipseでrubyのソースコードを編集するにはAptanaを使うのが一般的ですが、railsを使うわけでもなく、cssを編集するわけでもなく、ただ単純にrubyで10行程度のスクリプトを書くためにAptanaを入れるのはちょっと大げさですよね。

そんなときにはAptanaに含まれるRDTだけをインストールしてあげます。

公式での説明。

http://update1.aptana.org/rdt/3.2/index.html

プラグインのURL。

http://update1.aptana.org/rdt/3.2/site.xml

インストールが完了すれば、あとは Winodw > Open Perspective > Other から Ruby を選ぶだけ。eclipseでさくさくrubyのソースコードをいじれるようになり快適です。

ピモッターをリリースしたよ!

Posted by admin on Sunday, 13 September, 2009

こんな会話があったのが、12日の夜。

[2009/09/12 22:58:25] えがちゃんの発言: ひまだなーw
[2009/09/12 22:58:27] えがちゃんの発言: なにします?w
[2009/09/12 22:58:29] えがちゃんの発言: なんかサービスつくりたいw
[2009/09/12 23:03:57] tkosugaの発言: なんのサービス?
[2009/09/12 23:04:07] tkosugaの発言: この話に食いつく
[2009/09/12 23:04:25] えがちゃんの発言: pimoteのAPIをつかったサービスですねー

そこからbuzzterみたいなのを作りたいと言う話になりましたので、

颯爽とpimotterをリリースしました!この公開が13日19時30分ですので、話しが始まってからリリースまで21時間という速さです。

精度はまだまだ低いのですが、雰囲気は十分に感じ取ってもられるのではないかなと思います。

pimoteで流行しているキーワードを自動的に抽出し、それをピックアップして見ることができます。これでどんな事が流行しているのか一目で分かりますね!

このウェブサービスはrails 2.3.2 を使って作られています。pimoteサーバーには5分間隔で最新のタイムラインを取得しに行っています。画面に表示されるタイムライン解析結果はmemcachedを使って3分間キャッシュしてます。タイムラインの解析にはMeCabを使いました。

pimoteといいますか、twitterで流れる文章はほとんど口語で流れてるプラス、名詞だけ抜きだせば良いというものではないという事が分かってきました。

アスキーアートも抜き出せると良いのですが、パターンで一致させるぐらいしか方法が思いつきませんでした(ここは未実装です)

さっくりと作る分には誰が作っても同じような実装になると思うので、ここにこのサービスの中核となるMeCabで構文解析された単語の取り捨てをするコードを貼り付けます。

  #
  # もっとちゃんと作らないと。後で時間かけてかなー。
  #
  def self.necessary?(surface, feature, prev_feature)

    #p surface + ", feature:" + feature + ", prev_feature: " + prev_feature.to_s

    return false if surface.blank?
    return false if surface.split(//u).collect{|c| MARKS.include?(c)}.all?
    return false if /[[:cntrl:]|[:blank:]|[:punct:]]+/ =~ surface

    return true if (/^名詞,(一般|固有名詞|サ変接続|形容動詞語幹|ナイ形容詞語幹)/ =~ feature)
    return true if (/^形容詞,(自立)/ =~ feature)
    return true if (/^接頭詞,名詞接続/ =~ feature)
    return true if (/^感動詞/ =~ feature)

    return false if prev_feature.blank?

    #
    # この2つ次は絶対に拾う
    #
    if (/^接頭詞,名詞接続/ =~ prev_feature)
      return true
    end

    if (/^名詞/ =~ prev_feature)
      return true if (/^助詞,(.*,連語|終助詞|係助詞)/ =~ feature)
      return true if (/^動詞,(非自立)/ =~ feature)
    end

    if (/^助詞,格助詞,連語/ =~ prev_feature)
      return true if (/^助動詞/ =~ feature)
    end

    if (/^助詞,係助詞/ =~ prev_feature)
      return true if (/^助詞,終助詞/ =~ feature)
    end

    if (/^動詞,非自立/ =~ prev_feature)
      return true if (/^動詞,非自立/ =~ feature)
    end

    false
  end

  ASCII_ART_MARKS = %w{゚ ノ Д 冫}
  ASCII_MARKS   = %w{… ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ ^ _ ` { | } ~ > <}
  ZENKAKU_MARKS = %w{  、 。 , . ・ : ; ? ! ゛ ゜ ´ ` ¨ ^  ̄ _ ヽ ヾ ゝ ゞ 〃 仝 々 〆 〇 ー ― ‐ / \ ~ ∥ | … ‥ ‘ ’ “ ” ( ) 〔 〕 [ ] { } 〈 〉 《 》 「 」 『 』 【 】 + - ± × ÷ = ≠ < > ≦ ≧ ∞ ∴ ♂ ♀ ° ′ ″ ℃ ¥ $ ¢ £ % # & * @ § ☆ ★ ○ ● ◎ ◇ ◆ □ ■ △ ▲ ▽ ▼ ※ 〒 → ← ↑ ↓ 〓 ∈ ∋ ⊆ ⊇ ⊂ ⊃ ∪ ∩ ∧ ∨ ¬ ⇒ ⇔ ∀ ∃ ∠ ⊥ ⌒ ∂ ∇ ≡ ≒ ≪ ≫ √ ∽ ∝ ∵ ∫ ∬ Å ‰ # ♭ ♪ † ‡ ¶ ◯ ─ │ ┌ ┐ ┘ └ ├ ┬ ┤ ┴ ┼ ━ ┃ ┏ ┓ ┛ ┗ ┣ ┳ ┫ ┻ ╋ ┠ ┯ ┨ ┷ ┿ ┝ ┰ ┥ ┸ ╂ ∮ ∑ ∟ ⊿ ¦ ' " }
  MARKS = ASCII_MARKS + ZENKAKU_MARKS + ASCII_ART_MARKS

よそで書かれたテキストを自分のサーバーにもってきて加工するだけのサービスって楽ですね。負荷の問題もありませんし。接続先は1つですし。次からのサービスを作るときに、このあまりの楽々さに溺れてしまわないよう気をつけたいと思います。

railsでSEOするには?sitemap.xmlの生成とウェブマスタツールへの登録。

Posted by admin on Sunday, 6 September, 2009

railsに限らずですが、ウェブアプリケーションフレームワークでSEOについて言及されているのをあまり見ない気がします。

CMSの世界ではSEOが活発に行なわれており、1つ記事を書くだけでGoogle、Yahooが認識しやすくなるよう勝手にmetaタグ内の最適化やsitemap.xmlの更新を行なってくれるプラグインもあります。

先日公開した、クレジットカード・メーカーもSEOを意識して作ってあります。このアプリケーションはRubu on railsを使っていますので、実際に行なったSEOの内容を紹介して行きます。

Yahooサイトエクスプローラーに登録

Yahooサイトエクスプローラーに登録します。これに登録することで、Yahooでどのページがインデックスとして認識されているか、sitemapやrobots.txtの内容に誤りが無いかを知ることができます。

管理するサイトを登録すると、承認のためmetaタグを埋め込むかファイルを置くように言われますので、ここではmetaタグを埋め込みました。

<META name="y_key" content="xxxxxxxx" />

Googleウェブマスターツールに登録

GoogleもYahooサイトエクスプローラーのようなウェブマスタを支援するツールのGoogleウェブマスターツールを提供しています。

同じように、管理するサイトを登録すると、承認のためmetaタグを埋め込むかファイルを置くように言われますので、ここではmetaタグを埋め込みました。

<meta name="verify-v1" content="xxxxxxxx" />

bing Webmaster Centerに登録

上2つと同じようにBingにも同様のツールが公開されています。同じように登録して同じようにmetaタグを埋め込みます。

<meta name="msvalidate.01" content="xxxxxxxx" />

これで各検索エンジンでどのようにサイトを認識しているのかを知ることが出来ます。どのツールも登録から解析結果がでるまで最低で1週間はかかります。それまでは気長に待ちましょう。

サイトマップの生成

上記3つともにサイトマップを登録してあげます。サイトマップを作るツールとしてはxml-sitemapsが有名です。このツールで生成されるのは静的なサイトマップですので、動的なコンテンツが含まれている場合にはサイトマップも動的に生成しなければなりません。

まずサイトマップを返すコントローラーを作成します。

class SitemapController < ApplicationController
  def sitemap
    headers["Content-Type"] = "text/xml"
    headers["Last-Modified"] = Date.today.utc
    render :layout => false
  end
end

ビューはこのようにします。

xml.instruct!
xml.urlset "xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9" do

  if (request.port == 80)
    base_location = request.protocol + request.host
  else
    base_location = request.protocol + request.host + ":" + request.port.to_s
  end

  xml.url do
    xml.loc base_location + "/"
    xml.lastmod Image.find(:first, : order => "id desc").created_at.utc.xmlschema
  end

  xml.url do
    xml.loc base_location + "/new"
    xml.lastmod File.mtime(File.dirname(__FILE__) + '/../new/index.html.erb').utc.xmlschema
  end

  xml.url do
    xml.loc base_location + "/about"
    xml.lastmod File.mtime(File.dirname(__FILE__) + '/../about/index.html.erb').utc.xmlschema
  end

  Image.find(:all).each{|image|

    if (image.parent_id.blank?)
      xml.url do
        xml.loc base_location + "/card/#{image.id}"
        xml.lastmod image.created_at.utc.xmlschema
      end
    end
  }

end

動的ではない静的なページもあると思います。静的なページについては以下のようにそのファイルの更新日時を指定してあげるとよいでしょう。

xml.lastmod File.mtime(File.dirname(__FILE__) + '/../about/index.html.erb').utc.xmlschema

xml.lastmodに指定しているtimestamp.utc.xmlschemaの動作は以下のようになります。

>> Time.now
=> Sun Sep 06 19:59:10 +0900 2009
>> Time.now.utc
=> Sun Sep 06 10:59:13 UTC 2009
>> Time.now.utc.xmlschema
=> "2009-09-06T10:59:17Z"

サイトマップは一般的にはルート直下にsitemap.xmlという形で設置します。これを実現するためにroute.rbに以下を書き足します。

map.connect 'sitemap.xml', :controller => "sitemap", :action => "sitemap"

ここで作られたsitemap.xmlをそれぞれの検索エンジンのウェブマスターツールに登録します。

静的なコンテンツ中心のサイトではサイトマップ作っても意味はないのでしょうが、動的なコンテンツの場合は、このサイトマップとURLの正規化を合せて行なう事で検索エンジンがサイトのコンテンツを正しく認識してくれることに役に立たちます。

railsでのURLの正規化については以下サイトで説明がされています。合せて参照下さい。

http://www.seoonrails.com/

slicehostのcentos(5.2)にImageMagick(6.5.3-10)とRMagick(2.11.0)をインストール

Posted by admin on Sunday, 6 September, 2009

1つ前の記事と同じように、クレジットカード・メーカーが実稼動するcentos5.2でrmagickが動くようにします。

まず依存するライブラリをインストールします。

sudo yum install bzip2-devel freetype-devel libpng-devel libtiff-devel freetype-devel libjpeg-devel

ソースコードもってきてconfigureしてmakeしてinstall

wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-6.5.3-10.tar.gz
tar xvfz ImageMagick-6.5.3-10.tar.gz
cd ImageMagick-6.5.3-10

./configure --disable-static --with-modules --without-perl \
     --without-magick-plus-plus --with-quantum-depth=8 --disable-openmp

make
sudo make install

共有ライブラリを認識させます。

ldconfig

あとは以下を~/.bashrcに追記します。

export LD_LIBRARY_PATH=/usr/local/lib

gemでRMagickをインストール。

gem install rmagick -v 2.11.0

以上です。centosに入れるのは特に問題なくできました。

UbuntuにImageMagick(6.5.3-10)とRMagick(2.11.0)をインストールする

Posted by admin on Sunday, 6 September, 2009

クレジットカード・メーカーの開発はUbuntuで行ないました。そこでRMagickをインストールできるまですんなりとは行かなかったので備忘録としてブログ記事にします。

まず依存するライブラリをインストール。

sudo apt-get install libfreetype6
sudo apt-get install libfreetype6-dev
sudo apt-get install libjpeg62-dev
sudo apt-get install libpng12-dev
sudo apt-get install libwmf-dev
sudo apt-get install libperl-dev
sudo apt-get install libbz2-dev
sudo apt-get install libz-dev
sudo apt-get install libx11-dev
sudo apt-get install libxt-dev
sudo apt-get install libxext-dev
sudo apt-get install libxml2-dev
sudo apt-get install liblcms1-dev
sudo apt-get install libexif-dev
sudo apt-get install libjasper-dev
sudo apt-get install libltdl3-dev
sudo apt-get install graphviz
sudo apt-get install gs-gpl
sudo apt-get install pkg-config

wgetでソースコードを取得します。

wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-6.5.3-10.tar.gz
tar xvfz ImageMagick-6.5.3-10.tar.gz
cd ImageMagick-6.5.3-10

configure するときに –disable-openmpを足しました。

./configure --disable-static --with-modules --without-perl \
     --without-magick-plus-plus --with-quantum-depth=8 --disable-openmp

makeしてインストールします。

make
sudo make install

シンボリックリンクを更新します。

ldconfig

これをやらないとibMagickCore.so.2が見つからないとエラーがでます。

$ convert --version
convert: error while loading shared libraries: libMagickCore.so.2: cannot open shared object file: No such file or directory

正常にインストールできたことを確認。

$ convert --version
Version: ImageMagick 6.5.3-10 2009-08-04 Q8 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC

次にgemでRMagickをインストールします。

sudo gem install rmagick -v 2.11.0

irbから動作確認してみましょう。

require 'rubygems'
require 'RMagick'
require 'pp'

include Magick
pp colors

ずらーっと色情報が出力されれば完了です。

rails + passenger でファイルをアップロードするときに注意すること

Posted by admin on Sunday, 6 September, 2009

今回、クレジットカード・メーカーを作るにあたって、アップロードされたファイルの取り扱いに意外と気を使う必要がありました。上限を超えたばかでかいファイルが送られてくるケースや、ファイルの拡張子はpngでも内容はexeファイルであったりなどです。

ここではそれらに対して行なった設定と実装を説明します。

Apacheにアップロードするファイルサイズの上限を指定

クレジットカード・メーカーではアップロードできるファイルサイズの上限を1Mまでとしています。
このファイルサイズ以上をアップロードされても捨てるしかありませんので、リソースの無駄使いになってしまいます。

これを防ぐためにはApacheのLimitRequestBodyディレクティブを使います。

以下、上記ページからの抜粋です。

このディレクティブは、 管理者にクライアントからの異常なリクエストを制御できるようにし、 何らかの形のサービス拒否攻撃 (訳注:DoS) を避けるのに有効です。

ある場所へのファイルアップロードを許可する場合に、 アップロードできるファイルのサイズを 100K に制限したければ、 以下のように指定します:

LimitRequestBody 102400

アップロードされたファイルの種類を指定

アップロードされてきたファイルのMIMEタイプを判別し、それが背景画像として使えるかを判定しなければいけません。

MIMEタイプを判定するライブラリにはshared-mime-infoを使いました。

yumを使ってインストールするには以下のコマンドを実行します。

yum install shared-mime-info

rubyからshared-mime-infoを使えるように以下のコマンドを実行します。

gem install shared-mime-info

これでMIMEパッケージが使えるようになりますので、以下のコードでファイルの種類を知ることができます。

require 'rubygems'
require 'shared-mime-info'

MIME.check_magics('images/sample.jpg').type
=> "image/jpeg"

shared-mime-infoの仕様に、推奨するMIMEタイプのチェックする順番について書かれています。

簡単に書きますと、次の3ステップになります。

1. MIMEタイプを見る
2. glob(ファイルの拡張子)を見る
3. magic(ヘッダ部分のバイナリ)を見る

attachment-fuの使い方

クレジットカード・メーカーはカード画像の生成にImageMagickを使っています。railsプラグインのattachment-fuではサムネイルの生成にImageMagickを使っているためとても相性がよかったです。

以下のようにthumbnailsにファイルのサイズを書くだけでサムネイルを勝手に生成してくれます。

class PublishedImageFile < ActiveRecord::Base
  has_attachment(:content_type => :image,
                 :max_size => 1024.kilobytes,
                 :thumbnails => { :middle => '387x249', :small => '258x166'}
  )
end

このモデルのスキーマは以下のようになっています。

  create_table "published_image_files", :force => true do |t|
    t.integer  "parent_id"
    t.string   "content_type"
    t.string   "filename"
    t.string   "thumbnail"
    t.integer  "size"
    t.integer  "width"
    t.integer  "height"
    t.string   "name",                         :default => "オリジナルの"
    t.string   "comment",      :limit => 1024, :default => "自分だけのクレカ出来た!"
    t.boolean  "fixed"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "published_image_files", ["content_type"], :name => "index_published_image_files_on_content_type"
  add_index "published_image_files", ["created_at"], :name => "index_published_image_files_on_created_at"
  add_index "published_image_files", ["parent_id"], :name => "index_published_image_files_on_parent_id"

テーブル作って、モデル作って、has_attachmentと書くだけでアタッチメントの管理できるattachment-fuは素晴らしいです。モデルを削除すると保存先のストレージからも消してくれます。

以上です、railsでファイルをアップロードするサービスを作る方の参考になれば幸いです。

[rails]数字をselect-boxで選択させる

Posted by admin on Friday, 28 August, 2009

railsのselect-boxで数字を単純に選択させたいケースがありますよね、年齢とか0から100までのどれかを選択させるとか。

その時には以下のようにします。

collection_select(method, (0..100).to_a, "to_i", "to_i", :include_blank => false)

単純明快。数字が格納されているRangeを配列に変換して、それを”to_i”してもらいます。

このようにFormBuilderに入れて使用して下さい。

class MyFormBuilder < ActionView::Helpers::FormBuilder    

  def select_number(method)
    collection_select(method, (0..100).to_a, "to_i", "to_i", :include_blank => false)
  end

end

こういうのってrailsのhelperでこういうの最初から入ってなかったっけかなあ?と思ったりします。