スポンサーサイト

  • 2015.09.25 Friday

一定期間更新がないため広告を表示しています

  • -
  • -
  • -
  • スポンサードリンク

Capitrano 、Github 、etc.. 最近、お世話になった(勉強になった)リンク集

  • 2012.09.28 Friday
  • 01:17
最近、Web開発ブームにまたなってきて。ようやく「継続的開発&リリース環境」構築の重要性を理解できてきたので。。というか、理解させられた。というか。ようやく、Capistrano とか、Github とか、うまく使って「安心して、公開中のサービスの中に、次の機能開発を行う」準備ができつつあります。参考になったリンクを列挙します。ありがとうございました。


▼ Capistrano 関連
・自分が実践したチュートリアル
http://takemikami.com/technote/archives/646

・一般的チュートリアル
http://d.hatena.ne.jp/dkfj/20120228/1330434467
http://kitbc.s41.xrea.com/main/?try_capistrano

・Githubとの連携
http://www.oiax.jp/rails3book/prepare_capistrano2.html
http://blog.new-bamboo.co.uk/2008/3/12/github-with-capistrano

・さくらサーバとの連携
http://d.hatena.ne.jp/ntaku/20111115/1321358900

・Passengerとの連携
http://www.aaginskiy.com/technology/2011/02/deploying-rails-3-apps-with-capistrano/

・tmp public に保存している、画像やpkgファイルの保存場所設定、およびシンボリックリンク設定
http://www.slideshare.net/T2J/capistrano-tips-tips

・Delayed_job の対応
http://blog.digital-squad.net/article/244451741.html
https://github.com/collectiveidea/delayed_job/wiki/Rails-3-and-Capistrano
 ・Delayed_job: http://blog.nzm-o.com/item/222


▼ Git のことはじめ
・一般的情報
http://d.hatena.ne.jp/ryousanngata/20120119/1326906033
http://soohei.net/vpsgit-1/

・ローカルレポジトリからのデプロイ
http://blog.yabasoft.biz/archives/3592


▼ そのほか
・Rails から、Gmail 経由でメールを送る
http://bookmeter.que.jp/hakkyo/?date=20110830

・SQLのコラム(未読)
http://d.hatena.ne.jp/koseki2/20100915/HellSQL

・TODO(RedmineとGithubとの連携:うまくいかない・・・)
https://github.com/koppen/redmine_github_hook



以上。


つぎはたぶん、テスト環境とか。。勉強するハメになるんだろうな。orz..

結局、Rails 3.2 で 大量のデータを検索する場合、Sunspot な Solr が一番 いい感じ。という面白くないオチ。

  • 2012.06.10 Sunday
  • 17:16
前回のエントリーで、Elasticsearch を、 tire で実装してみて。日本語の扱いがイケてない。という事実に直面し。。もちろん、Geekなあなたなら、なんとかしちゃうのかもしれませんが、エセ Geek な私は、そそくさと別の道を探ってみたわけです。

で、やっぱり落ち着いたのは Rails 3.2 + Sunspot + Solr 。Solr は、デフォルトの設定で普通に日本語扱えます。前回 Elasticsearch で出会ったように「中日」と検索して「中村」が引っかかることはありません。普通に、何不自由なく、MySQLで like 検索するように、日本語を扱えます。

Railsとの連携について。Sunspot の他にも選択肢があるみたいだけど。Google先生で質問しやすいのは、 Sunspot。とは言っても、英語でないと初心者向けの質問&回答は見つからないけど。。





以下、Rails 3.2 にて、インストールから実装(development 環境)まで参考にした情報。っていうか、Github 内の、オフィシャルドキュメント。 → Quickstart with Rails 3

1) Gemfile に、以下記載
gem 'sunspot_rails'
gem 'sunspot_solr' # development環境で使う、Solr のパッケージ。インストール推奨!
※ もし、Java が入ってない環境なら、先にインストールが必要だと思います。詳しくは、前回の Elasticsearch のエントリーを参照してください。

2) バンドルインストール
bundle install


3) デフォルトのコンフィグファイルを生成する
rails generate sunspot_rails:install


4)「1」にてインストールした Solr を起動する
bundle exec rake sunspot:solr:start # バックグラウンドでなくフォアグラウンドで起動するには「 sunspot:solr:run 」


5) model オブジェクトを、index に追加するための「searchable」ブロックを指定(以下、設定例)。
class Post < ActiveRecord::Base
 searchable do
  text :title, :body
  text :comments do
   comments.map { |comment| comment.body }
  end

  boolean :featured
  integer :blog_id
  integer :author_id
  integer :category_ids, :multiple => true
  double :average_rating
  time :published_at
  time :expired_at

  string :sort_title do
   title.downcase.gsub(/^(an?|the)/, '')
  end
 end
end

※「text」で指定したフィールドは、全文検索対象になります。controller ファイル内で「with」や「facet」で絞込み的にテキストを扱いたい場合は「string」で設定する必要があります。
※ Sunspot で扱えるクラスは、APIドキュメントのType項にて説明されています。ページ中央の「Defined Under Namespace」のところに書いてあります。

6) コントローラの指定(例)。
Post.search do
 fulltext 'best pizza'

 with :blog_id, 1
 with(:published_at).less_than Time.now
 order_by :published_at, :desc
 paginate :page => 2, :per_page => 15
 facet :category_ids, :author_id
end


7) 全文検索の、細かな設定(例)。
# 'pizza' を含む、すべての`text`フィールド (:title, :body, or :comments) のposts が対象
Post.search { fulltext 'pizza' }

# 'pizza' を含むpostsで、特に title 内で見つかったらスコアを上げる(優先させる)
Post.search do
 fulltext 'pizza' do
  boost_fields :title => 2.0
 end
end

# ':featured'(上記「5」のモデルファイル内の「searchable」で設定している boolean 値)が true の posts の場合、スコアを上げる(優先させる)
Post.search do
 fulltext 'pizza' do
  boost(2.0) { with(:featured, true) }
 end
end

# :title に'pizza' が含まれる posts だけを対象にする
Post.search do
 fulltext 'pizza' do
  fields(:title)
 end
end

# :title に pizza が含まれる posts をスコアを上げる(優先させる)。:body に含まれる場合は、スコアを上げない。
Post.search do
 fulltext 'pizza' do
  fields(:body, :title => 2.0)
 end
end



7-1) 全文検索での、フレーズ(Phrases)について。Solr は、近くに並んだ(close together な)単語を「フレーズ」として検索可能にする。Sunspotが使う、デフォルトのquery parser (dismax)では、フレーズ検索は、「" (ダブルクウォート)」で囲むことで有効となる。(→参考
# "great pizza" というフレーズを含んだ posts を検索する
Post.search do
 fulltext '"great pizza"'
end


7-2) 全文検索で、「 query_phrase_slop 」を使えば、フレーズ内の単語と単語の間に割り込める(入ってよい)単語を指定できる。
# フレーズ内の単語の間に、1単語のみ割り込み可能。つまり"great big pizza" も、検索対象となる。
Post.search do
 fulltext '"great pizza"' do
  query_phrase_slop 1
 end
end



7-3) 全文検索で、接近した単語のスコアを上げる。その単語は、必ずしもフレーズの中にある必要はないが、フレーズの中にあった方が、よりスコアは高くなる。
# 「great」と「pizza」を含んだドキュメントにマッチする。もし :title フィールド内のフレーズに、その単語が含まれれば、そのドキュメントのスコアは、より高くなる。
Post.search do
 fulltext 'great pizza' do
  phrase_fields :title => 2.0
 end
end

# 「great」と「pizza」を含んだドキュメントにマッチする。:title フィールドの中のフレーズ(あいだに1単語挟んでもOK)にその単語が含まれれば、そのドキュメントのスコアは、より高くなる。
Post.search do
 fulltext 'great pizza' do
  phrase_fields :title => 2.0
  phrase_slop 1
 end
end



8) スコープ (Scalar フィールド)について。全文検索の対象となる「text」以外(例:integer / boolean / time / etc...)の型は、検索クエリの範囲を指定したり、制限したりするのに使われる。ちなみに、全文検索よりも先に実行される。
# blog_id が 1 となる posts
Post.search do
 with(:blog_id, 1)
end

# 平均値が、3.0 〜 5.0 の posts
Post.search do
with(:average_rating, 3.0..5.0)
end

# category_id が、「1」「 3」「 5」のどれかにマッチする posts
Post.search do
with(:category_ids, [1, 3, 5])
end

# 1週間前にパブリッシュされた、posts
Post.search do
with(:published_at).greater_than(1.week.ago)
end


8-1) 「〜を含まない」というタイプのスコープ
# category_id が、 1 でも 3 でもないカテゴリー
Post.search do
 without(:category_ids, [1, 3])
end

# 「8)」のサンプルは、すべて「without」を使って「〜以外」とすることが可能。


8-2) 「Disjunctions」と「Conjunctions」(→参考
# 有効期限(expired)のない posts。もしく(OR)は、有効期限前の posts
Post.search do
 any_of do
  with(:expired_at).greater_than(Time.now)
  with(:expired_at, nil)
 end
end

# blog_id が「1 」で(AND)、author_idが「2」の posts
Post.search do
 all_of do
  with(:blog_id, 1)
  with(:author_id, 2)
 end
end


Disjunctions と conjunctions は、組み合わせも可能
Post.search do
 any_of do
  with(:blog_id, 1)
  all_of do
   with(:blog_id, 2)
   with(:category_ids, 3)
  end
 end
end


8-3) 全文検索の結果を含んだオブジェクトに対し、スコープによって範囲指定/制限をすることが可能
# blog_idが「1」で(AND)、 'pizza' を :title に含む posts
Post.search do
 with(:blog_id, 1)
 fulltext("pizza")
end



9) ページネーション( Pagination )について。Solr の検索結果は、すべてページ分割されている。検索結果の配列は、will_paginate や kaminari のようなページネーションライブラリと、シームレスに連動することができるメソッドを mixed in している。Sunspot はデフォルトで、Solr の検索結果の、最初の30件をリクエストする。
search = Post.search do
 fulltext "pizza"
end

# 全60件の検索結果があるとして。30件/1ページだとすると、全2ページとなる
results = search.results  # => Array with 30 Post elements

search.total  # => 60

results.total_pages  # => 2
results.first_page?  # => true
results.last_page?  # => false
results.previous_page  # => nil
results.next_page  # => 2
results.out_of_bounds?  # => false
results.offset  # => 0



次の結果のページを取得するため、検索(search)再度行い、paginate メソッドを使う。
search = Post.search do
 fulltext "pizza"
 paginate :page => 2
end

# 全60件あるとして。今回は 2ページ目が対象だ
results = search.results # => Array with 30 Post elements

search.total  # => 60

results.total_pages  # => 2
results.first_page?  # => false
results.last_page?  # => true
results.previous_page  # => 1
results.next_page  # => nil
results.out_of_bounds?  # => false
results.offset  # => 30


「 paginate: 」に「 :per_page 」オプションをつけると、結果ページ内の表示件数をカスタマイズできる
search = Post.search do
 fulltext "pizza"
 paginate :page => 1, :per_page => 50
end



10) ファセット(Faceting)とは、検索条件や絞り込み条件にマッチしたドキュメントの数を限定するための、Solr の機能だ。ドリルダウン型の検索インターフェイスを作る際などに使える。各 facet は、0 以上の row を返す。各 row は、検索結果 を絞り込む条件となる。
「 field facets 」の場合、各 row は、対象フィールド の特定の値 を 表す。「 query facets 」の場合、各 row は、不特定のスコープ を表す。実のところ、 facet とは、スコープの論理的グループにすぎない。

10-1) Field Facets
# 'pizza' にマッチした posts を、:author_id ごとにカウントして返す
search = Post.search do
 fulltext "pizza"
 facet :author_id
end

search.facet(:author_id).rows.each do |facet|
 puts "Author #{facet.value} has #{facet.count} pizza posts!"
end


10-2) Query Facets
# 平均値を、ファセットにより範囲指定した posts (のグループ)
Post.search do
 facet(:average_rating) do
  row(1.0..2.0) do
   with(:average_rating, 1.0..2.0)
  end
  row(2.0..3.0) do
   with(:average_rating, 2.0..3.0)
  end
  row(3.0..4.0) do
   with(:average_rating, 3.0..4.0)
  end
  row(4.0..5.0) do
   with(:average_rating, 4.0..5.0)
  end
 end
end

# 例)
# 平均値が、1.0 〜 2.0 のposts : 2件
# 平均値が、2.0 〜 3.0 のposts : 1件
search.facet(:average_rating).rows.each do |facet|
 puts "Number of posts with rating withing #{facet.value}: #{facet.count}"
end



11) 表示順( Ordering )について。標準では、Sunspot は "score" に基づいた表示順となる。ちなみに "score" とは、Solr 判断による、相対的な基準だ。ソートは「order_by」メソッドを使って実現する。
# 平均値(降順 - descending - )でソート
Post.search do
 fulltext("pizza")
 order_by(:average_rating, :desc)
end

# :score の相関によってソートする。相関が同点の場合、平均値(:average_rating)が高いものを上にする。
Post.search do
 fulltext("pizza")

 order_by(:score, :desc)
 order_by(:average_rating, :desc)
end

# Randomized ordering
Post.search do
 fulltext("pizza")
 order_by(:random)
end



12) Geospatial
TODO


13) 結果のハイライト( Highlighting )について。ドキュメント内の、検索クエリにマッチした部分を強調表示することができる。ハイライトしたいフィールドは「 :store 」する必要がある。
class Post < ActiveRecord::Base
 searchable do
  # ...
  text :body, :stored => true
 end
end


例えば、 :body フィールドにマッチした場合に、ハイライトするには。
search = Post.search do
 fulltext "pizza" do
  highlight :body
 end
end

# ハイライトのされ方は、こんな感じ;
# Post #1
# 私は、本当に *pizza* が大好きだ。
# *Pizza* は、私の好物だ
# Post #2
# ペペロニ *pizza* って、おいしいなあ。
search.hits.each do |hit|
 puts "Post ##{hit.primary_key}"

 hit.highlights(:body).each do |highlight|
  puts " " + highlight.format { |word| "*#{word}*" }
 end
end



14) Functions
TODO

15) More Like This
TODO


16) インデックスの、細かい点。
あとでやる。

16-1) スコアを上げるのは、インデックスの時に!( Index-Time Boosts )
どんなクエリの時にも、スコアを上げたいフィールドは、インデックスの時に :boost 設定をしよう
class Post < ActiveRecord::Base
 searchable do
  text :title, :boost => 5.0
  text :body
 end
end



17) Stored Fields について。 :stored したフィールドは;
・ Solr の内部でも 元のまま(tokenized されてない/ analyzed されてない)の値を保つ
・ 元となる Database(通常はSQL)を参照することなく、データを取得することができる。ハイライトするのにも使われる。
class Post < ActiveRecord::Base
 searchable do
  text :body, :stored => true
 end
end

# Database を参照することなく、:stored されたコンテンツを取得する
Post.search.hits.each do |hit|
 puts hit.stored(:body)
end



18) 「 #hits 」と「 #results 」
Sunspot はオブジェクトの型や Primary Key を Solr に保存する。検索結果を取得する際、Primary Key は、実際のオブジェクト(通常は、SQL の Database)をロードするために使われる。
#「 #results 」 を使って、オブジェクト・リレーショナル・マッパー(以下、ORM。 ORMの例としては、ActiveRecord + SQL のDatabase がある)から、該当レコードを取得する
Post.search.results.each do |result|
 puts result.body
end


元となるDatabase にクエリを投げずに、検索結果の情報にアクセスするには「 #hits 」を使う
# 「 #hits 」を使って、ORM からオブジェクトをロードすることなく、すべての情報を Solr から取得する
Post.search.hits.each do |hit|
 puts hit.stored(:body)
end


ORM からロードする「 #results 」と、ファセットやハイライトなど「 #hits 」の両方が必要な場合、「 each_with_result 」というコンビニメソッドが用意されている
Post.search.each_hit_with_result do |hit, result|
 # ...
end



19) 再インデックス( Reindexing Objects )について。Rails を使っていれば、 save のコールバックの一部として、オブジェクトは Solr に勝手に インデックスされる。ただし、「 searchable 」ブロック内のスキーマを変更した場合は、すべての オブジェクトの再インデックス( reindex )を行い、 Solr に変更を反映させる必要がある。
bundle exec rake sunspot:solr:reindex

# もしくは、特定のバッチサイズで、特定のモデルに対して再インデックスするなら
bundle exec rake sunspot:solr:reindex[500,Post]  # shell によっては、 [ with ¥[ and ] with ¥] をエスケープする必要がある



20) Use Without Rails
TODO


21) Solr のパラメータを、手動で設定するには、「 adjust_solr_params 」を使う
Post.search do
 adjust_solr_params do |params|
  params[:q] += " AND something_s:more"
 end
end



22) Session Proxies
TODO

23) Type Reference
TODO (→ 参照:APIドキュメントのType項


24) 開発について( Development )

24-1) 「 sunspot 」で、テストする。まず必要とされる gem をインストールする
cd /path/to/sunspot/sunspot
bundle install


Solr のインスタンスを、port 8983 で立ち上げる
bundle exec sunspot-solr start -p 8983
# フォアグラウンドでの実行は → `bundle exec sunspot-solr run -p 8983`


テストをはしらせる
bundle exec rake spec


必要があれば、Solr のインスタンスを止める
bundle exec sunspot-solr stop


24-2)「 sunspot_rails 」で、テストする。まず必要とされる gem をインストールする
cd /path/to/sunspot/sunspot
bundle install


Solr のインスタンスを、port 8983 で立ち上げる
bundle exec sunspot-solr start -p 8983
# フォアグラウンドでの実行は → `bundle exec sunspot-solr run -p 8983`


sunspot_rails のディレクトリに移動して
cd ../sunspot_rails


テストをはしらせる
rake spec # Rails の全バージョン
rake spec RAILS=3.1.1 # 特定バージョンの Rails だけ


必要があれば、Solr のインスタンスを止める
cd ../sunspot
bundle exec sunspot-solr stop




以上、Github 内の、オフィシャルドキュメント。 → Quickstart with Rails 3








ちなみに。ちょっと使ってて、便利だなあと思ったのは「 has_many :through 」とかのレベルまで Sunspot が理解してくれて、インデックスを作ってくれること。例えば、以下の様な感じ;
class Event < ActiveRecord::Base
 attr_accessible :xxxxxxx, :xxx, :xxxxx, :xxxxx, :xxxx, :xxxxxxx

 belongs_to :mother
 has_many :kids
 has_many :grandchildren, :through => :kids

 searchable do
  text :xxxx
  integer :xxxx
  string :xxxxxx

  string :xxxxxx, :multiple => true do  #子要素は、複数あるから、multiple
   kids.map(&:xxxxxx)
  end

  time :xxxxxxt, :trie => true, :multiple => true do
   grandchildren.map(&:xxxxxx)
  end
end

こんな感じで「has_many, :through」とかが設定されてれば、いきなり「grandchildren」とか出しても理解してくれるんです。






あと、こっちも参照。 →  Adding Sunspot search to Rails in 5 minutes or less

1) Gemfile 内に、以下記載
gem 'sunspot_rails', '~> 1.3.0'

2) バンドルインストール
$ bundle install

3) config/sunspot.yml を生成
$ rails g sunspot_rails:install

※ もし、Java が入ってない環境なら、先にインストールが必要だと思います。詳しくは、前回の Elasticsearch のエントリーを参照してください。

4) 現在の環境(おそらく development)で、solr を起動する
$ rake sunspot:solr:start

※ http://localhost:8982/solr/admin/ にて、Solr を操作することが可能。

5) model ファイルに、検索対象の記述を追加する(以下、例。)
class Post < ActiveRecord::Base
 searchable do
  text :title, :default_boost => 2
  text :body
 end
end


6) 検索用の index を作成する(※ ActiveRecord を使って保存されたデータについては、以後自動的に index に追加されるけど、初回なのでこれまでのデータを追加するために実行。)
$ rake sunspot:reindex


7) controller ファイルに、検索メソッドを追加する(以下、例。)
class PostsController < ApplicationController
 def search
  @search = Post.search(:include => [:comments]) do
   keywords(params[:q])
  end
 end
end


8) view ファイルに、検索部分を追加する(以下、Hamlでの例。)
.results
 - @search.each_hit_with_result do |hit, post|
  .result
   %h2= h post.title
   %h6== (#{h hit.score})
   %p= h truncate(post.body, :length => 100)
.pagination
 = will_paginate(@search.results)




以上、Adding Sunspot search to Rails in 5 minutes or less






あと。以下も参考になりました。

・『 Date range facets with Sunspot in Ruby on Rails 』
→ 日付を、ある範囲内で検索するような場合は、「 :trie => true 」を指定。「 time 」のみ対応( date では :trie を指定できない)。ちなみに、Database 上は、datetime を使ってると思いますが、その中に NULL( もしくは「0000-00-00 00:00:00」かも)があると「 $ rake sunspot:reindex 」した時に「 rake aborted! sunspot Error: Invalid Date String:'' 」みたいに出るから注意。日付の欄には、きちんと値を入れておく必要がある。みたい。
class Event
 searchable do
  time :start_time, :trie => true
 end
end

Event.search do
 facet :start_time do
  bod = Time.zone.now.beginning_of_day
  row :today do
   with :start_time, bod..(bod + 1)
  end
  row :tomorrow do
   with :start_time, (bod + 1)..(bod + 2)
  end
  # etc.
 end
end








あと。まだ詳しく診てないけど。 #hits を使った実例;
『Sunspot, Solr, Rails: Working with Results』






こちらも。実装のイメージを把握するのに、いい感じの実例;
『Full-text search in Rails with Sunspot』






こちらも、導入の参考にしました;
Railscast『 #278: Sunspotで全文検索 』






ちなみに Solr にはよさげな日本語の書籍があります。→『Apache Solr入門 ―オープンソース全文検索エンジン』。Rails関連の記述は古いですが、Solrについて理解を深めるには、良さ気な本だと思います。





・・・ぱーーーっと急いで書いたたので、誤字脱字。勘違いしてるぞ!などは、コメントくださいませ orz..
JUGEMテーマ:インターネット


Rails3.2 tire を使って、Elasticsearch を使うまでの道のり

  • 2012.05.28 Monday
  • 18:31
JUGEMテーマ:インターネット


ここのところ、すっかり検索エンジン放浪者になってしまいました。 今回Railsで作ったアプリで扱うDBが巨大なので、MySQLのqueryベースだと、もたもたして使えない。というのが出発点でした。

で、まず発見したのが「Think Sphinx」。なんか、センスがよくて、いいなーっと思って。実装までしてみたんですが。なんと、日本語苦手なんですね、この人。はじめは、ぜんぜん日本語扱えなくて。で「Sphinx Search in Japanese」を参考に設定したら、なんとか扱えるようにはなったのだけれど。検索精度が悪い。。コンフィグ設定でできる範囲でいじってみたのですが、やっぱりイケてない。 日本語扱えない以外は、かなり好きなタイプなんだけど。でも、だめみたい。 ちなみに、PDFのチュートリアル(有料)があるんだけど、それがすごく読みやすい。英語だけど。 日本語、もうちょっとちゃんと扱ってくれたらなあ・・・。

で、いろいろ検索してたら「Sunspot」と「Tire」が有力候補としてあがってきました。

The Ruby Toolboxでも、その3つが巨塔みたい。Solr系もいいんだけど、なんとなく古いイメージがあって。だからまあ、枯れてていいのかもしれないけど。新しもの好きなので、Elasticsearchをまず使ってみようと思ったわけです。



以下、Centos6(さくら VPS)へのインストール記録です;
(※Ruby 1.9.3 や、Rails 3.2 、MySQL など基本的な構成で、既存のアプリケーションがあるという前提での記述です。)



1)まず、Javaをインストールしてない場合は、Java Runtime の最新版をダウンロードしてインストールします。(サーバ内のターミナルからDLしようとすると、いわゆる規約に同意するためのJSでエラーになってしまい。うまくいきせんでした。なので、ローカルにDLしてから、サーバにSFTPしました。)
http://download.oracle.com/otn-pub/java/jdk/7u4-b20/jre-7u4-linux-x64.rpm

2)ダウンロードしたファイルを、適当なディレクトリにコピーして、インストールします。
$ sudo rpm -ivh jre-7u4-linux-x64.rpm


3)バージョンの確認をしてみます。
$ java -version
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b20)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)




4)次に、elasticsearch をDLします。
$ curl -L -O -k ╲ https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.19.4.zip


5)解凍します
$ unzip elasticsearch-0.19.4.zip


6)適当に、移動します
$ sudo mv elasticsearch-0.19.4 /usr/local/elasticsearch


7)実行してみます
$ /usr/local/elasticsearch/bin/elasticsearch -f


※終了するには「Control + C」で落とします。
※「./elasticsearch/bin/service/elasticsearch start | stop | restart」が可能な、Service wrapper もあり。詳しくは、下記「参考」参照
※参考)「Setting up elasticsearch」



8)rails_app/Gemfile に、下記追加
gem 'tire'
gem 'will_paginate', '~> 3.0' # 既に記載済みの場合はOK。これ入れないと「elasticsearch 」でインデックス作るときに「undefined method `paginate'」みたいなエラーがでる。後述参照


9)バンドルインストール
bundle install


10)rails_app/config/environment.rb に以下追加
require 'will_paginate'

※参考)https://github.com/radiant/radiant/issues/221

11)検索対象の model ファイルに、記述追加
class Article < ActiveRecord::Base
has_many: xxxxx

include Tire::Model::Search #これを追加
include Tire::Model::Callbacks #これを追加
end

※参考)https://github.com/karmi/tire/blob/master/README.markdownの中の「ActiveModel Integration」

12)検索対象の controller ファイルの index メソッドをこんな感じに;
def index
if params[:query].present?
@shows = Show.search(params[:query], load: true)
else
@shows = Show.all
end

 ・
 ・
 ・
end


13)検索対象の view ファイルを、こんな感じに(※models_pathは適切に差し替える);
<%= form_tag models_path, :method => :get do %>


<%= search_field_tag :query, params[:query] %>
<%= submit_tag "Search", name: nil %>


<% end %>



14)elasticsearch の index を更新する
rake environment tire:import CLASS='Model名' FORCE=true

※参考)rake -T でコマンド確認可能

15)検索ボックスが表示されているので、そこから検索可能(な、はず)


・・・でもなんか、2〜3文字で検索すると、その中の1文字だけが一致する結果もひろってきたりと、あんまり信頼性ない感じ。例えば「中日」で検索すると「中国」とか「中村」がかかってくる。「中 AND 日」で検索すると、なんとかうまくいくけど。それでいいんかい? やっぱ、Solr なのか?それとも、elasticsearch の設定でなんとかなるのか??


以上、参考URL;
Elasticsearch 公式サイト
tire on Github
RailsCasts #306 ElasticSearch Part 1(日本語)




Rails3.2 の migration で「id」を autoincrement でなくする設定メモ

  • 2012.05.17 Thursday
  • 14:23
JUGEMテーマ:インターネット


Railsで、外部のデータをインポートしてサービスを構築するような場合、デフォルトの migration で TABLE を作ると、自動的に autoincrement な、PRIMARY KEY の設定された、int(11) の「id」というフィールドが作られる。これは、一から作るサービスにおいては便利だけれど、どこかからデータをひっぱってくるようなサービスでは、不都合のある場合もある。

そんな時は、migration の時に、デフォルトで作られる「id」を無効にして、自分で「id」を設定すればいいみたい。

migration ファイルにて;
class CreateUsers < ActiveRecord::Migration
 def self.up
  create_table :users, :id=>false do |t|
   t.column :id, "int(11) PRIMARY KEY"
   t.timestamps
  end
 end

 def self.down
  drop_table :users
 end
end

引用(&一部修正)『Auto IncrementでないPrimary Key列を作りたい』
参考)『マイグレーション(migrate)で主キーのないテーブル、id以外の主キーを持つテーブルを作る』

「t.column」と一緒に、「t.timestamps」とか「t.string」が並ぶのはなんか気持ち悪いなあと思ったけど。でも、動くのでいいか。


Active Record 関連、勉強し直さないとなあ。。。


勉強すること)
RailsGuide『Active Record Associations(翻訳)』
『今さらRails3メモ - その5: Model Association -』

Rails の データ型と、MySQL のデータ型の対応

  • 2012.05.15 Tuesday
  • 18:53
JUGEMテーマ:コンピュータ


Railsのデータ型について、うろ覚えだったので、調べたメモです。

Rails シンボルMySQL 型
:binaryblob
:booleantinyint(1)
:datedate
:datetimedatetime
:decimaldecimal
:floatfloat
:integerint(11)
:stringvarchar(255)
:texttext
:timetime
:timestampdatetime



元ネタには、Ruby Class についてもまとまっててさらに便利です。
→ 『 MySQL and Ruby on Rails datatypes


はやく、Rails終わってiOSのコード書きたい・・・

Rails 2.3 環境で、search_do(hyperestraier)と will_paginate を使って、全文検索を実現しようとした件

  • 2010.01.07 Thursday
  • 20:34
 Rails 2.3 環境で、search_do(hyperestraier)と will_paginate を使って、全文検索を実現しようとして。検索フォームから検索させて、結果表示するとこまでは成功したんだけど。結果をさらに絞り込んで表示するとことかがうまくできない。でもとりあえず、できたとこまでメモ。


▼1)will_paginate をインストール

http://wiki.github.com/mislav/will_paginate/installation


1-1)config/environment.rb を編集;

--------

| Rails::Initializer.run do |config|

| # ↑と end の間に、下記config.gem 〜 'http://gemcutter.org' の行を追加

|   config.gem 'will_paginate', :version => '~> 2.3.11', :source => 

'http://gemcutter.org'

| end

--------


1-2)コマンド実行で、gemsをインストール

# rake gems:install



▼2)hyper estraier のインストールと、設定

http://hyperestraier.sourceforge.net/nguide-ja.html

http://www.kugimiyabyou.net/2009/08/01/hyper-estraier%E3%81%A8rails%E3%82%92%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%A6rails%E3%81%8B%E3%82%89%E5%85%A8%E6%96%87%E6%A4%9C%E7%B4%A2/



2-1)Fedoraなので、yumでインストール可能

# yum install hyperestraier


2-2)設定ファイルやインデックスなどを格納するディレクトリを作成(Railsアプリ直下に作成しました)

# estmaster init casket


2-3)ノードマスタの起動

# estmaster start casket


2-4)Web管理画面でユーザ作成など実行

http://localhost:1978/master_ui


※ default ID/PW = admin / admin


2-5)chkconfigに登録(サーバ起動時に同時に起動させる)

http://i-am.web777.net/2007/02/hyperestraier.html

http://makisuke.seesaa.net/article/6066867.html


/etc/ini.d/hyperestraier ファイルを作成

------------

| #!/bin/bash

| #

| # chkconfig: 35 98 02

| # description: HyperEstraier NodeMaster daemon

| # processname: estmaster

| # config: /var/hyperestraier/estmaster/_conf

|

| # Source function library.

| . /etc/rc.d/init.d/functions

|

| # Source networking configuration.

| . /etc/sysconfig/network

|

| RETVAL=0

| prog="estmaster"

|

| ESTUSER="estraier(実行するユーザ名)"

| ESTMASTER="/usr/bin/estmaster(/usr/local/bin/estmasterとかの可能性もあり)" 


| ESTCONF="(initで作成したディレクトリを指定)"

|

| if ! [ -x $ESTMASTER ]; then

|        echo $ESTMASTER is not executable.

|         exit 1

| fi

|

| start()

| {

|         if [ -e /var/lock/subsys/$prog ]; then

|                echo "now $prog running!"

|                 echo "if $prog is not running, remove 

¥"/var/lock/subsys/$prog¥""

|                 exit 1

|         fi

|

|         echo -n $"Starting $prog:"

|         sudo -u $ESTUSER $ESTMASTER start -bg $ESTCONF

|         RETVAL=$?

|        if [ $RETVAL -eq 0 ]; then

|                 daemon true

|                 touch /var/lock/subsys/$prog

|         else

|                 daemon false

|         fi

|         echo

| }

|

| stop()

| {

|         echo -n $"Stopping $prog: "

|         sudo -u $ESTUSER $ESTMASTER stop $ESTCONF

|         RETVAL=$?

|         if [ $RETVAL -eq 0 ]; then

|                 daemon true

|                 rm -f /var/lock/subsys/$prog

|         else

|                 daemon false

|         fi

|         echo

| }

|

| case "$1" in

|         start)

|                 start

|                 ;;

|         stop)

|                 stop

|                 ;;

|         restart)

|                 stop

|                 start

|                 ;;

|         *)

|                 echo $"Usage: $0 {start|stop|restart}"

|                 RETVAL=1

| esac

| exit $RETVAL

------------


とりあえず;

# service hyperestraier start




▼3)search_do のインストールと、設定

http://d.hatena.ne.jp/shunsuk/20090406/1239020647


3-1)gitでインストール(git:// だと通らない環境の場合、http:// に書き換えて実行)

# script/plugin install git://github.com/moro/search_do.git


3-2)config/database.ymlを編集

------------

| development:

|   adapter: mysql

|   encoding: utf8

|  database: test

|   pool: 5

|   username: test

|   password: test

| #以下を記載(node は、2-2で指定した名称)

|   estraier:

|     host: localhost

|     user: admin

|     password: admin

|     port: 1978

|     node: casket

------------


3-3)ソースのメンテ

http://d.hatena.ne.jp/shunsuk/20090324/1237893278


※vendor/plugins/search_do/lib/search_do/backends/hyper_estraier.rbを編集



▼4)model / controller / view の編集


4-1)modelの編集

http://github.com/grosser/search_do/blob/7c4d06da26c9ef3d45c21377dc864f9ca112d094/README.rdoc


------------

| class User < ActiveRecord::Base

|   acts_as_searchable(

|     #fields the will be found in fulltext search

|     :searchable_fields => [:name,:website,:city,:about],

|     #fields used for attribute search/ordering

|     :attributes => {:name=>nil,:city=>nil,:country=>nil,:age=>nil}

|   )

|   attr_accessor :html_snippet #add this to get html snippets on your 

results (see below)

| end

------------



4-2)script / consoleで確認

http://www.kugimiyabyou.net/2009/08/01/hyper-estraier%E3%81%A8rails%E3%82%92%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B%E3%81%A6rails%E3%81%8B%E3%82%89%E5%85%A8%E6%96%87%E6%A4%9C%E7%B4%A2/


# ./script/console

Loading development environment (Rails 2.3.3)

>> User.reindex!

=> [#, #, #]

>> User.fulltext_search("ぱん")

=> [#]

>>



4-3)controllerに、検索用アクションを追加

------------

| def fulltext_search

|   @users = User.paginate (params[:search],

|                           :order => params[:order],

|                           :page => params[:page],

|                           :per_page => 20,

|                           :total_users => 

User.count_fulltext(params[:search]),

|                           :finder => 'fulltext_search'

|                           )

|   respond_to do |format|

|     format.html # index.html.erb

|     format.xml  { render :xml => @user }

|   end

| end

------------



4-4)viewに、検索フォームを追加

------------

| <% form_tag({ :controller => "users", :action => "fulltext_search"}) 

do -%>

|   <%= text_field_tag('search', params[:search]) -%>

|   <%= submit_tag("検索") -%>

| <% end -%>

------------



5)今後の課題


・fulltext_searchで検索した結果に対し、さらに絞込み検索できるようにする

 (↑やってみたけど、よーわからんかった...)


・pagenate がうまく動作してないのをなおす


・検索インデックスの更新(User.reindex!)を、script/runner から定時実行する





【随時更新】RailsGuide 訳『Rails 国際化対応 - I18n API』

  • 2010.01.02 Saturday
  • 16:56
Rails 2.2 / 2.3 に搭載されている、Railsアプリを国際化対応させる機能 I18n API について、RailsGuideに分かりやすそうな説明があったので翻訳しています。必要があれば随時更新していこうと考えています。Railsやプログラムについて、シロウトなので、表現が間違っている箇所もあるかもしれません。お気づきの点があれば、ぜひコメントくださいませ。

ちなみに、当初は『翻訳プロジェクト:RailsGuide日本語翻訳』で作業していました。。。

------------

Rails の国際化 (I18n) API

Rubyのgem『I18n(iとn間の文字 _internationalization_ を省略した表記)』はRails 2.2よりRuby on Railsに付属され始めました。アプリケーションを英語だけでなく、他言語に翻訳することや、アプリケーションの多言語化をサポートする、カンタンで、拡張性のあるフレームワークです。

「国際化」プロセスとは、文字や(日付や通貨のフォーマットなどの)各国固有の事情をアプリケーションから取り除く(抽象化する)という意味で使われることが多い。

「ローカル化」プロセスは、翻訳し、各国固有の事情を反映することを意味する。

Railsアプリケーションを「国際化」するために、やらなければならないのは: 

* I18nを利用する 
* [ロケール]辞書の場所を指定する 
* [ロケール]のセットする/しない、切り替え方法を指定する

 アプリケーションを「ローカル化」するには、以下の3つが必要です: 

*Railsデフォルトの[ロケール]を置き換える、補完する -- 例)日付、時間のフォーマット。月の呼び方、Active Recordのmodel名。その他 
*アプリケーション中の文字列を、key化された辞書に抽出(抽象化)する。-- 例)flashメッセージ、view中の文章、その他。 
*できあがった辞書を、どこかに保存する このガイドでは、I18n APIの概要を説明し、Railsアプリケーションの国際化を、初心者でもわかるチュートリアルで説明していきます。 

------------ 
注意: Ruby I18n フレームワークは、Railsアプリケーションの国際化/ローカル化に必要なすべてを提供します。ただし、もっと機能を追加したいなら、プラグインや機能拡張を使うことができます。詳しい情報はRails "I18n Wiki":http://rails-i18n.org/wiki を参照してください。
 ------------ 


1)I18nは、どうRuby on Railsで機能するか 

国際化には、複雑な問題が付きまとう。言語はそれぞれ、様々な面で異なっている(例:複数形の扱いなど)ので、一度に全てを解決するツールは提供できない。

そこで、Rails I18n APIでは、以下にフォーカスする: 

*英語と、それに似た言語は、始めから使えるようしておく
*その他の言語は、カスタマイズを簡単にし、全てを拡張可能にすることで対応する

Railsフレームワーク中の、スタティックな文字列は全て国際化されていますが、それもI18nの機能を使っています -- 例)Active Recordのバリデーションメッセージ、時間や日付のフォーマットなど --。Railsアプリケーションのローカル化とは、デフォルト値に「乗っかる」ことを意味します。


1.1)ライブラリの全体構成

Ruby I18n gem は、2つの要素で構成されています:

*i18n公開API -- ライブラリの動作を定義する、public methodを含んだRuby module。
*これらのmethodを実行する、デフォルトのバックエンド(_Simple_backend と命名) 利用する時には、public methodしかアクセスできないけれど、I18nのバックエンドの能力・機能を知っておくと何かと便利です。

------------ 
注意: 標準のSimple backendを、より強力なもの(RDBMに訳語を保存できるもの、GetText辞書、もしくは類似したもの)に置き換えることは可能だし、望まれているかもしれません。後述する "別のバックエンドを使う":#using-different-backends を参照してください。
------------ 


1.2)I18n公開API 

I18n APIの、もっとも重要なmethodは次の通りです:  
------------
|  translate # 翻訳したい文章を指定
|  localize # 日時のオブジェクトをローカル化
------------
上記2つは、#t と #l のエイリアスです。以下のように使います: 
------------
|  I18n.t 'store.title'
|  I18n.l Time.now 
------------

 以下の属性にも、reader / writer が用意されています:
------------
|  load_path # 辞書ファイルの在り処を指示する
|  locale # 現在のロケールの取得、指定
|  default_locale # デフォルト地域の取得、設定
|  exception_handler # 別のexception_handlerを使う 
|  backend # 別のbackendを使う
------------

 それでは、次の章で、簡単なRailsアプリケーションの国際化をやってみましょう! 


2)Railsアプリケーション国際化の準備

I18nの起動/運用には、いくつかの簡単な手順が必要です


2.1)I18nモジュールの設定 

「設定より規約」哲学に従い、Railsの各種デフォルト設定はリーズナブルです。もし別の設定にしたければ、簡単な方法で上書きすればよいでしょう。 config/localesにある.rb.ymlのfilesを、Railsは自動的に翻訳のload pathに追加します。 

デフォルトの[ロケール] である en.yml には、シンプルな2つの翻訳設定が含まれています。
------------
|  en: 
|   hello: "Hello world"
------------

:en [ロケール]では、helloキー が、"Hello world"という文字列にマッピングされています。Rails内の文字列は、すべてこの方法で国際化されています。例えば、Active Recordのバリデーションメッセージ(activerecord/lib/active_record/locale/en.yml)を見てください。また、日付フォーマット(activesupport/lib/active_support/locale/en.yml)も見てください。YAMLやRubyの標準的なHashを使って、デフォルトのバックエンド(Simple backend)に訳語を保存できます。

I18nライブラリーのデフォルトロケールは、英語です。他の地域を設定しなければ、:en が翻訳に用いられます。 

------------
注意: i18nライブラリは(数々の議論を経て )、[ロケール]のキーについて、実用的なアプローチをとるようになりました。:en:pl のように、("言語")[ロケール]だけを含み、"言語"と"地域設定"、"方言"などを分けて扱う:en-US や :en-UK のようなアプローチをとっていません。国際化されたアプリケーションの多くは[ロケール]に、+:cz+ や +:th+ 、+:es+ (チェコ語、タイ語、スペイン語)のように、"言語"だけを使うでしょう。でも、言語圏の中にある地域差が重要な場合もあります。:en-US [ロケール]の通貨記号は $ だけれど、:en-UK では です。:en-UK のように、地域を区別し、完全に"English - United Kingdom"でローカル化するのもよいでしょう。様々なRails I18n plugins(例えば、Globalize2)を参考にするとよいでしょう。
------------

翻訳のload path( I18n.load_path ) は、自動的に読み込まれる翻訳ファイルへのパスが書かれたRubyの配列です。辞書/翻訳ファイルには、自分が理解しやすい名前をつけて構わないでしょう。

------------
 注意: バックエンドが、初回の翻訳を読み込む速度は、速くありません。This makes it possible to just swap the backend with something else even after translations have already been announced. 
------------

デフォルトの environment.rb には、地域別辞書ファイルの追加方法、デフォルト地域をどうやって変更するのかが書かれています。必要な箇所のコメントアウトを外し、編集するだけで利用可能です。

------------
| # The internationalization framework can be changed 
| # to have another default locale (standard is :en) or more load paths. 
| # All files from config/locales/*.rb,yml are added automatically. 
| # config.i18n.load_path << Dir[File.join(RAILS_ROOT, 'my', 'locales', '*.{rb,yml}')]
| # config.i18n.default_locale = :de
------------


2.2)オプション: I18nの設定カスタマイズ

何らかの理由で environment.rb を使いたくない場合についても、説明しておきましょう。マニュアル設定でも、なんとかなるはずです。

I18nライブラリーに、作成した翻訳ファイルの場所を教えます。load pathは、アプリケーションのどこにあっても構いません。ただし翻訳の際、常に起動されるので注意が必要です。デフォルトの地域を変更したい場合、"initializer"に、以下を追加するのがシンプルです:

------------
# in config/initializer/locale.rb
| # I18nに翻訳ファイルの場所を教える
| I18n.load_path << Dir[ File.join(RAILS_ROOT, 'lib', 'locale', '*.{rb,yml}') ] 
| # デフォルトの地域を、:en igai 以外にする
| I18n.default_locale = :pt 
------------


2.3)[ロケール]の設定、引き回し

英語以外の言語、1種類だけを(デフォルト[ロケール])として翻訳する場合、I18n.default_localeの設定を、environment.rb 、もしくは上で説明した"initializer"に記述しましょう。設定は、requestの間中有効です。

複数の[ロケール]をサポートしたい場合は、requestの間、設定を引き回す必要があります。

sessionやcookie の中に、選択された[ロケール]を保存するという誘惑にかられているかもしれません。が、そうしてはなりません。ローカル化は、ユーザが意識することなく実行(transparent)されるべきなので、URLの一部に含まれる必要があります。ユーザがWebに抱く、基本的な期待(例:友達にURLを送れば、当然その友達は同じページ、同じ内容を見るはず)を壊してはいけません。"RESTful" とよく説明されるのがこれです。RESTfulについては、"Stefan Tilkov's articles"を読むと理解が深まります。RESTfulのルールについて、いくつか例外があるので、これから見ていきましょう。

setting partは、簡単です。ApplicationControllerの、before_filterに、以下のように設定しましょう:

------------
| before_filter :set_locale
|  def set_locale
|  # params[:locale] が nil なら I18n.default_locale が使われる
|  I18n.locale = params[:locale]
| end
------------

この場合、指定した[ロケール]を、URLクエリーとして引き回す必要があります。

- http://example.com/books?locale=pt (←これはgoogleと同じ方法です)。
- http://localhost:3000?locale=pt はポルトガル語のローカル化情報を、
- http://localhost:3000?locale=de はドイツ語のローカル情報を、といった感じです。

URLに個別のローカル化情報を入れてリロードするページにしたいなら、次の章を飛ばして、アプリケーションの国際化に進んでください。

 [ロケール]を、アプリケーションのすべてのURLに入れるのが嫌か、もしくはURLの見た目を違った風にしたい場合(例:http://example.com/pt/books と http://example.com/en/book)について考えてみましょう。

次の例は、+["en", "es", "gr"]+のような文字列を含んだ配列として、対応可能なローカル化情報を持っている場合のものです。Rails2.2に、この機能は含まれていません。2.3には、available_localesというaccessorが含まれる予定です。(このコミットと、その背景にある "Rails I18n Wiki" を参照してください)

Rails2.2で対応可能な[ロケール]を持つには、initializerに以下のような対応が必要です:

----------
| # config/initializers/available_locales.rb 
| # 
| # ローカル化情報を便利にロードさせる
| # 参照: http://rails-i18n.org/wiki/pages/i18n-available_locales 
| module I18n
|  class << self
|   def available_locales;
|    backend.available_locales;
|   end
|  end
|  module Backend
|   class Simple
|    def available_locales;
|     translations.keys.collect { |l| l.to_s }.sort;
|    end
|   end
|  end
| end
| # 読み込まれたローカル化情報を、強制的に初期化する必要あり
| I18n.backend.send(:init_translation)
| AVAILABLE_LOCALES = I18n.backend.available_locales
| RAILS_DEFAULT_LOGGER.debug "* Loaded locales: #{AVAILABLE_LOCALES.inspect}"
----------

次に、ApplicationControllerの中で簡単にアクセスできるよう、定数をラップします

----------
| class ApplicationController < ActionController::Base
|  def available_locales;
|   AVAILABLE_LOCALES;
|  end
| end
----------

 
2.4)ドメイン名から、ローカル化情報をセットする

ドメイン名から、[ロケール]をセットすることもできます。例えば、
- www.example.com の場合、英語(もしくはデフォルト)をロードさせたい、
- www.example.es の場合は、スペイン語をロードさせたいというように。
つまり、top-levelドメイン名を[ロケール]に利用するのです。これにはいくつかの利点があります: 

*[ロケール]が、URLの一部として明確である
*どの言語でコンテンツが表示されるか、本能的に理解できる
*実装は、Railsのよくやる方法で可能
*検索エンジンは、異なる言語のコンテンツで、内部リンクの貼られた別のものだと認識してくれる。

ApplicationControllerでは、次のように実装できます:

------------
| before_filter :set_locale
|  def set_locale
|   I18n.locale = extract_locale_from_uri
|  end
|  # ローカル化情報を、top-levelドメインから得る。
|  # 対応可能なローカル化情報がなければ、nilを返す
|  # /etc/hosts ファイルに、以下のような記載を加える: 
|  # 127.0.0.1 application.com
|  # 127.0.0.1 application.it 
|  # 127.0.0.1 application.pl 
|  def extract_locale_from_tld
|   parsed_locale = request.host.split('.').last 
|   (available_locales.include? parsed_locale) ? parsed_locale : nil
|   end
------------

サブドメインから、似たような方法で[ロケール]をセットできる: 

------------
| # ローカル化コードを、requestのサブドメインから得る
| # (例: http://it.application.local:3000) 
| # 以下のような感じで:
| # 127.0.0.1 gr.application.local 
| # /etc/hosts ファイルに記載し、ローカル化する
| def extract_locale_from_subdomain
|  parsed_locale = request.subdomains.first
|  (available_locales.include? parsed_locale) ? parsed_locale : nil
| end
------------
 
アプリケーションの中で、地域を切り替えるメニューを付けるなら、こんな感じです:

------------
| link_to("Deutsch", "#{APP_CONFIG[:deutsch_website_url]}#{request.env['REQUEST_URI']}")
------------

APP_CONFIG[:deutsch_website_url]には、http://www.application.deのような値を設定するとします 

この方法は、前述したとおり利点がありますが、別ドメインで地域別(言語別バージョン)サービスを提供できない / 考えられないでしょう。それを解決法するには、ローカル化コードをURLのパラメータ(もしくはパス)に入れ込みましょう。


2.5)URLパラメータによる、ローカル化設定 

ローカル化情報の設定と、引き回しは、URLパラメータに入れて行うのが普通です。最初の例で、I18n.locale = params[:locale]  _before_filter_ としたように。URLはwww.example.com/books?locale=ja 又は www.example.com/ja/books という感じになります。

この方法は、ドメイン名から[ロケール]を設定するのと同じ利点があります。RESTfulだし、World Wide Webの慣習とも親和性が高いです。ただし、実装はもっと複雑です。

params から[ロケール]を取得し、セットするのは簡単です。複雑なのは、すべてのURLに[ロケール]を埋め込み、requestをまたいで引き回す部分です。明示的に、すべてのURLに link_to( books_url(:locale => I18n.locale)) といったコードを入れるのは、退屈だし、多分ムリです。

Railsの「動的URLの集中管理・決定」機構が ApplicationController#default_url_options にあります。これは有用で大切なシナリオです:url_for  による、"デフォルト"設定、および(url_forの実装/オーバーライドによる)helperメソッド利用可能にします。 

ApplicationControllerに、以下を加えます:

------------
| # app/controllers/application_controller.rb
| def default_url_options(options={})
|  logger.debug "default_url_options is passed options: #{options.inspect}¥n"
|  { :locale => I18n.locale }
| end
------------

すべてのhelperメソッドは、url_for に依存しています。(例: named routesのhelper「+root_path+」や「+root_url+」、resource routesのhelper「+books_path+」や「+books_url+」、etc) は、queryの文字列中に自動的に[ロケール]を含むようになっています ー 例) http://localhost:3001/?locale=ja. 

これで満足かもしれませんね。しかし、ローカル化のための「おともだち」が、全てのURLの最後に付くと、URLの可読性に影響します。さらに言えば、構造的な視点から[ロケール]は、ほかのアプリケーション要素よりも上位概念と考えるのが普通です。URLはこの視点を反映する必要があります。

URLを「 www.example.com/en/books(英語のローカル化情報を読み込む場合)」や「 www.example.com/nl/books(オランダのローカル化情報を読み込む場合)」のようにしたいのではないでしょうか。default_url_options のオーバーライドで実現できます:routeの設定を、path_prefix オプションで下記のようにします;

------------
| # config/routes.rb
| map.resources :books, :path_prefix => '/:locale'
------------

books_path を呼び出すと、デフォルト[ロケール]として /en/books が返されるでしょう。http://localhost:3001/nl/books のようなURLは、オランダの[ロケール]を読み込みます。以降、 books_path の呼び出しで /nl/books を返さなければなりません(なぜなら[ロケール]が変更されているからです)。

もちろん、最上位のURL(通常"HOMEPAGE"や"DASHBOARD")には特別な注意を払う必要があります。http://localhost:3001/nl のようなURLが勝手に動作するわけではありません。なぜなら、routes.rb ファイルの、map.root :controller => "dashboard" は、[ロケール]を考慮していないからです。(最上位のURLは、一つしかないので当然ですね) 

URLマッピングを、次のようにする必要があります: 

------------
| # config/routes.rb
| map.dashboard '/:locale', :controller => "dashboard"
------------

 routeの順番に、特に注意しましょう。こう指定すれば、他に影響を与えません。(map.rootの指定の前に直接追加したいかもしれません。)

この方法には、今のところ大きな副作用があります。_default_url_options_の実装の影響で、+:id+オプションを明示的に引き回す必要があり(例:link_to 'Show', book_url(:id => book))、Railsのコードマジック(例:link_to 'Show', book )の恩恵に与かれません。問題があれば、routeの動作をシンプルにしてくれる2つのプラグイン:Sven Fuchs's "routing_filter" と Raul Murciano's "translate_routes"を調べてみましょう 。Rails i18n Wikiにある、"How to encode the current locale in the URL"も参考になります。


2.6)クライアント側の情報により、ローカル化情報をセットする

特定のケースでは、(URLではなく)クライアント側の情報から[ロケール]をセットするのが良いこともあります。例えば、ブラウザで設定されている言語、IPアドレスから導かれる地理的な位置、もしくはアプリケーションでユーザに選択してもらい、プロフィールとして登録してもらうことなどです。Webサイトではなく、WebベースのアプリケーションやWebサービスでは、適した方法でしょう。既出の sessions cookies 、RESTful 構造についてのコラムボックスを参照して下さい。

<b>2.6.1) Accept-Languageを使う</b>

HTTP headerの Accept-Language は、クライアント側から提供される情報のひとつです。ブラウザや、(curlのような)他のクライアントに設定されていることがあります。

Accept-Language headerの実装は、次のようになるでしょう: 

------------
| def set_locale
|  logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
|  I18n.locale = extract_locale_from_accept_language_header
|  logger.debug "* Locale set to '#{I18n.locale}'"
| end
| private
| def extract_locale_from_accept_language_header
|  request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
| end
------------

 もちろん、production 環境では、もっと堅固なコードが必要になります。Iain Heckerのプラグイン"http_accept_language" や Ryan TomaykoのRack ミドルウェア "locale"を使うのもありです。


2.6.2)GeoIPや、類似のデータベースを活用する

クライアントから[ロケール]を得るために、クライアントのIPと地域情報をマッピングするデータベースを活用する方法もある。"GeoIP Lite Country"のようなデータベースだ。仕組みは、既出のコードのものとほとんど同じだ。データベースに、ユーザのIPをクエリで投げれば、ローカル化情報を国/地域/都市として返してくれるだろう。 


2.6.3)ユーザのプロフィール

You can also provide users of your application with means to set (and possibly over-ride) the locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above -- you'd probably let users choose a locale from a dropdown list and save it to their profile in the database. Then you'd set the locale to this value.


3)アプリケーションの国際化

以上でRuby on Railsアプリケーションを、I18n対応にするための準備は完了し、どう[ロケール]セットし、request間で引き回す方法も学びました。本当に面白いのは、これからです。

早速、アプリケーションを国際化しましょう。地域に特化した部分を抽出し、ローカル化していきます。抽出したら、適切な翻訳をします。

アプリケーションは、だいたいこんな感じです:

------------
| # config/routes.rb
| ActionController::Routing::Routes.draw do |map|
|  map.root :controller => 'home', :action => 'index'
| end
| # app/controllers/home_controller.rb
| class HomeController < ApplicationController
|  def index
|   flash[:notice] = "Hello flash!"
|  end
| end
| # app/views/home/index.html.erb
| <h1>Hello world!</h1>
| <p><%= flash[:notice] %></p>
------------



3.1)翻訳の追加

英語でローカル化された、2つの文字列があるのがわかります。コードを国際化するには、その文字列を置換すればよいのです。キーに対応したRailsの #t helper で国際化してみましょう。

------------
| # app/controllers/home_controller.rb
| class HomeController < ApplicationController
|  def index
|   flash[:notice] = t(:hello_flash)
|  end
| end
| # app/views/home/index.html.erb
| <h1><%=t :hello_world %></h1>
| <p><%= flash[:notice] %></p>
------------

このviewをレンダリングすると、:hello_world :hello_flash というキーに対応する翻訳情報が見つからないというエラーメッセージが出ます。


------------
注意: t (translate) helperメソッドがviewに追加されるので、I18n.t と毎回書かなくても大丈夫です。加えて言うと、このhelperは、翻訳情報を発見できなかった場合のエラーを捕捉し、<span class="translation_missing">の中に結果のエラーメッセージをwrapします。
------------

それでは、見つからなかった翻訳情報を、辞書ファイルに加え、「国際化」を実行します。

------------
| # config/locales/en.yml
| en:
|  hello_world: Hello World
|  hello_flash: Hello Flash
| # config/locales/pirate.yml
| pirate:
|  hello_world: Ahoy World
|  hello_flash: Ahoy Flash
------------

どうでしょう。default_localeを変更していないので、I18n は英語を使っているのではないでしょうか。

アプリケーションは次のようになっています:


private というローカル情報を、URLに渡す ( http://localhost:3000?locale=pirate )と、次のようになります:


------------
注意: ローカル化ファイルを追加したら、サーバを再起動する必要があります。
------------


YAML ( .yml ) か Ruby ( .rb ) ファイル形式で、SimpleStoreの中に翻訳情報を保存することが可能です。YAMLは、Rails開発者の間で好まれる形式ですが、大きな欠点があります。YAMLは、スペースと特定の文字に、大変過敏です。その影響で、正しく辞書が読み込まれない場合があります。Rubyファイルは、初回のrequestで、アプリケーションをクラッシュさせるため、何が悪いのか明確に把握できるのです。(YAMLで変な挙動に直面したら、辞書の内容をRubyファイルに移して試してみましょう。)


3.2)日付/時間フォーマットの追加

ではここで、viewにタイムスタンプを追加し、日付/時間をローカル化するデモをしてみます。時間のフォーマットをローカル化するには、Timeオブジェクトを I18n.l に渡すか、もしくはRailsの #l helperを使うことになるでしょう。 :format オプションで、フォーマットを指定できます。標準では、 :default フォーマットが使われます。

------------
| # app/views/home/index.html.erb
| <h1><%=t :hello_world %></h1>
| <p><%= flash[:notice] %></p>
| <p><%= l Time.now, :format => :short %></p>
------------

そして、我らの"海賊(pirate)"用翻訳ファイルに、timeフォーマットを追加しましょう。(英語をデフォルトにしたファイルが既にあるでしょう。)

------------
| # config/locales/pirate.yml
| pirate: 
|   time: 
|    formats: 
|    short: "arrrround %H'ish"
------------

結果はこうなります:


------------
TIP: ここまでくると、日付/時間フォーマット以外にも、I18n が裏方として変換してくれる要素を、追加したくなるかもしれません(少なくとも、"海賊"向けのローカル化をするために)。ひょっとしたら、あなた以外の誰かが、Rails自国語翻訳バージョンを作ってくれているというありがたいことになっているかもしれません。"Githubのrails-i18nレポジトリ"を見ると、様々なローカル化ファイルが蓄積されています。 config/locales/  ディレクトリにコピーして、利用可能です。
------------


3.3)Viewのローカル化

Rails 2.3では、便利なローカル化機能が追加されています:ローカル化viewテンプレートです。 BooksController というのがあったとしましょう。その index actionは、app/views/books/index.html.erb のテンプレートにコンテンツをレンダリングします。[ロケール]が、:es と指定されれた際、ローカルバージョン( index.es.html.erb )を同じディレクトリに置くだけで、Railsは index.html.erb テンプレートにコンテンツをレンダリングします。デフォルトでは、index.html.erb でviewはレンダリングされます。(将来的には、public などにあるファイルにも、同じような 自動化の魔法 が使えるようになるでしょう。) 

この機能を活用するのは、例えば、たくさんの静的情報を扱う場合です。辞書(YAMLやRubyファイル)の中に情報を全て入れ込むのは煩雑だからです。ただし、後からテンプレートを修正したくなった場合、作業はどっと増えることにはなるので注意しましょう。


3.4)ローカル化ファイルの構成

i18nライブラリに標準搭載されている、SimpleStoreを使う場合、翻訳情報は通常のテキストファイルとしてディスクに保存されます。アプリケーション内の全ての翻訳情報を一つのファイルにすると、メンテナンスが困難になります。階層化するなどして、複数のファイルで保存するのがよいでしょう。

config/locales が以下のような場合:

 |-defaults
 |---es.rb
 |---en.rb
 |-models
 |---book
 |-----es.rb
 |-----en.rb
 |-views
 |---defaults
 |-----es.rb
 |-----en.rb
 |---books
 |-----es.rb
 |-----en.rb
 |---users
 |-----es.rb
 |-----en.rb
 |---navigation
 |-----es.rb
 |-----en.rb

この場合、modelと、modelの属性名をviewの中のテキストから引き離すことができます。デフォルトの場合と同じですね(例:日付や時間のフォーマット)。i18nライブラリ向けに保存される他のものは、このような分け方とは別次元で提供されます。

------------
注意:指定のない限り、 [ロケール]はネストされたディレクトリから読み込んで起動されません。起動させるためには、以下のように明示的に指定します:
------------

------------
# config/environment.rb 
 config.i18n.load_path += Dir[File.join(RAILS_ROOT, 'config', 'locales', '**', '*.{rb,yml}')]
------------

翻訳機能の管理に使えるツールは、"Rails i18n Wiki" でチェックしましょう。 


4)I18n API の機能概要

ここまでで、i18nライブラリーの使い方は十分理解されたことでしょう。普通のRailsアプリケーションを国際化するための、重要なポイントは全て把握できているはずです。この章では、その理解を深めるための情報を提供していきます。

以下の機能について説明します: 

*"訳"の検索
*辞書へのデータ挿入
*"訳"を複数形にする
*日付、数値、通貨、その他のローカル化


4.1)"訳"の検索

4.1.1)基本的な検索方法、スコープ、入れ子状態のキー

Symbolか"文字列"のどちらかをキーに、"訳"は検索されます。以下の呼び出しは同じ意味です:

------------
| I18n.t :message
| I18n.t 'message' 
------------

translate メソッドには、 :scope というオプションがあります。このオプションは、"namespace"を特定する一つ以上の付加的なキーを持ち、キーのスコープも指定できます。 

------------
I18n.t :invalid, :scope => [:activerecord, :errors, :messages]
------------

これにより、Active Recordのエラーメッセージの中から、無効な( :invalid )メッセージを探します。 さらに、キーとスコープは、ピリオドで区切ったキーで特定することも可能です:

------------
 I18n.translate :"activerecord.errors.messages.invalid"
------------

以下の呼び出しは、全て同じ意味となります:

------------
| I18n.t 'activerecord.errors.messages.invalid' 
| I18n.t 'errors.messages.invalid', :scope => :active_record 
| I18n.t :invalid, :scope => 'activerecord.errors.messages' 
| I18n.t :invalid, :scope => [:activerecord, :errors, :messages]
------------

デフォルト設定  :default オプションが付くと、訳が見つからなかった場合、指定したvalueを返すようになります。

------------
| I18n.t :missing, :default => 'Not here' 
| # => 'Not here'
------------

:default のvalueがSymbolの場合、キーとして扱われ、訳されます。標準では、一つで複数のvalueを持つことができます。valueとなる一つ目は、returnされます。

次の例は、はじめ+:missing+キーを訳そうとし、次に+:also_missing+キーを訳します。それぞれは、resultをyieldしないため、"Not here"がreturnされます:

------------
| I18n.t :missing, :default => [:also_missing, 'Not here']
| # => 'Not here'
------------


4.1.3)Bulk and Namespace Lookup

複数の訳を一括で探す場合、キーの配列で受け渡すことができます:

-----------
| I18n.t [:odd, :even], :scope => 'activerecord.errors.messages'
| # => ["must be odd", "must be even"]
-----------

キーは、"訳"を集めたhash(入れ子にすることも可能)で移すこともできます。 全ての Active Record のエラーメッセージを、hashとして受け取るには:

-----------
| I18n.t 'activerecord.errors.messages'
| # => { :inclusion => "is not included in the list", :exclusion => ... }
-----------


4.1.3)"怠惰な" 検索

Rails 2.3 は、viewの中から、ローカル化情報を探すことができます。以下のような辞書を持っていたとします:

-----------
es: 
  books: 
  index: 
   title: "Título"
-----------

books.index.title というvalueを、app/views/books/index.html.erb テンプレートの中から、(ピリオドを記載して)探すことができます:

-----------
<%= t '.title' %>
-----------


4.2)埋め込み

多くの場合、辞書を抽象化し、変数を訳の中に埋め込みたくなるでしょう。I18n APIでは、埋め込み機能を提供しています。

#translateに渡される、:default :scope 以外のオプションは、訳の中に埋め込むことが可能です。

-----------
| I18n.backend.store_translations :en, :thanks => 'Thanks {{name}}!'
| I18n.translate :thanks, :name => 'Jeremy' # => 'Thanks Jeremy!'
-----------

翻訳の際、:default :scope を埋め込み変数として使おうとすると、I18n::ReservedInterpolationKey の例外が発生します。訳の中で埋め込み変数を使いたいけれど、#translate に受け渡していない場合、I18n::MissingInterpolationArgument の例外が発生します。


4.3)複数形にする

英語の場合、ある文字列について、単数形がひとつ、複数形がひとつしか存在しない。例)"1 message" と "2 messages"。他の言語("アラビア語", "日本語", "ロシア語", などなど) は異なった文法を持ち、2つや、それ以上の複数形をもっています。I18n API は、柔軟に複数形化する機能で、様々な言語に対応します。

:count の埋め込み変数は、"訳"に埋め込まれている点、CLDRに定義されているルールで"複数形"を検索するという2点で特別な役割をもっています:

------------
| I18n.backend.store_translations :en, :inbox => { 
|  :one => '1 message', 
|  :other => '{{count}} messages' } 
| I18n.translate :inbox, :count => 2 
| # => '2 messages' 
------------

:en の、複数化アルゴリズムは次の通りシンプルです:

------------
| entry[count == 1 ? 0 : 1]
------------

I.e. the translation denoted as +:one+ is regarded as singular, the other is used as plural (including the count being zero). If the lookup for the key does not return a Hash suitable for pluralization, an +18n::InvalidPluralizationData+ exception is raised. h4. Setting and Passing a Locale The locale can be either set pseudo-globally to +I18n.locale+ (which uses +Thread.current+ like, e.g., +Time.zone+) or can be passed as an option to +#translate+ and +#localize+. If no locale is passed, +I18n.locale+ is used: <ruby> I18n.locale = :de I18n.t :foo I18n.l Time.now </ruby> Explicitely passing a locale: <ruby> I18n.t :foo, :locale => :de I18n.l Time.now, :locale => :de </ruby> The +I18n.locale+ defaults to +I18n.default_locale+ which defaults to :+en+. The default locale can be set like this: <ruby> I18n.default_locale = :de </ruby> h3. How to Store your Custom Translations The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2] For example a Ruby Hash providing translations can look like this: <ruby> { :pt => { :foo => { :bar => "baz" } } } </ruby> The equivalent YAML file would look like this: <ruby> pt: foo: bar: baz </ruby> As you see, in both cases the toplevel key is the locale. +:foo+ is a namespace key and +:bar+ is the key for the translation "baz". Here is a "real" example from the Active Support +en.yml+ translations YAML file: <ruby> en: date: formats: default: "%Y-%m-%d" short: "%b %d" long: "%B %d, %Y" </ruby> So, all of the following equivalent lookups will return the +:short+ date format +"%B %d"+: <ruby> I18n.t 'date.formats.short' I18n.t 'formats.short', :scope => :date I18n.t :short, :scope => 'date.formats' I18n.t :short, :scope => [:date, :formats] </ruby> Generally we recommend using YAML as a format for storing translations. There are cases, though, where you want to store Ruby lambdas as part of your locale data, e.g. for special date formats. h4. Translations for Active Record Models You can use the methods +Model.human_name+ and +Model.human_attribute_name(attribute)+ to transparently look up translations for your model and attribute names. For example when you add the following translations: <ruby> en: activerecord: models: user: Dude attributes: user: login: "Handle" # will translate User attribute "login" as "Handle" </ruby> Then +User.human_name+ will return "Dude" and +User.human_attribute_name("login")+ will return "Handle". h5. Error Message Scopes Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes, and/or validations. It also transparently takes single table inheritance into account. This gives you quite powerful means to flexibly adjust your messages to your application's needs. Consider a User model with a +validates_presence_of+ validation for the name attribute like this: <ruby> class User < ActiveRecord::Base validates_presence_of :name end </ruby> The key for the error message in this case is +:blank+. Active Record will look up this key in the namespaces: <ruby> activerecord.errors.models.[model_name].attributes.[attribute_name] activerecord.errors.models.[model_name] activerecord.errors.messages </ruby> Thus, in our example it will try the following keys in this order and return the first result: <ruby> activerecord.errors.models.user.attributes.name.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank </ruby> When your models are additionally using inheritance then the messages are looked up in the inheritance chain. For example, you might have an Admin model inheriting from User: <ruby> class Admin < User validates_presence_of :name end </ruby> Then Active Record will look for messages in this order: <ruby> activerecord.errors.models.admin.attributes.title.blank activerecord.errors.models.admin.blank activerecord.errors.models.user.attributes.title.blank activerecord.errors.models.user.blank activerecord.errors.messages.blank </ruby> This way you can provide special translations for various error messages at different points in your models inheritance chain and in the attributes, models, or default scopes. h5. Error Message Interpolation The translated model name, translated attribute name, and value are always available for interpolation. So, for example, instead of the default error message +"can not be blank"+ you could use the attribute name like this : +"Please fill in your {{attribute}}"+. * +count+, where available, can be used for pluralization if present: |_. validation |_.with option |_.message |_.interpolation| | validates_confirmation_of | - | :confirmation | -| | validates_acceptance_of | - | :accepted | -| | validates_presence_of | - | :blank | -| | validates_length_of | :within, :in | :too_short | count| | validates_length_of | :within, :in | :too_long | count| | validates_length_of | :is | :wrong_length | count| | validates_length_of | :minimum | :too_short | count| | validates_length_of | :maximum | :too_long | count| | validates_uniqueness_of | - | :taken | -| | validates_format_of | - | :invalid | -| | validates_inclusion_of | - | :inclusion | -| | validates_exclusion_of | - | :exclusion | -| | validates_associated | - | :invalid | -| | validates_numericality_of | - | :not_a_number | -| | validates_numericality_of | :greater_than | :greater_than | count| | validates_numericality_of | :greater_than_or_equal_to | :greater_than_or_equal_to | count| | validates_numericality_of | :equal_to | :equal_to | count| | validates_numericality_of | :less_than | :less_than | count| | validates_numericality_of | :less_than_or_equal_to | :less_than_or_equal_to | count| | validates_numericality_of | :odd | :odd | -| | validates_numericality_of | :even | :even | -| h5. Translations for the Active Record +error_messages_for+ Helper If you are using the Active Record +error_messages_for+ helper, you will want to add translations for it. Rails ships with the following translations: <yaml> en: activerecord: errors: template: header: one: "1 error prohibited this {{model}} from being saved" other: "{{count}} errors prohibited this {{model}} from being saved" body: "There were problems with the following fields:" </yaml> h4. Overview of Other Built-In Methods that Provide I18n Support Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers. Here's a brief overview. h5. Action View Helper Methods * +distance_of_time_in_words+ translates and pluralizes its result and interpolates the number of seconds, minutes, hours, and so on. See "datetime.distance_in_words":http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L51 translations. * +datetime_select+ and +select_month+ use translated month names for populating the resulting select tag. See "date.month_names":http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15 for translations. +datetime_select+ also looks up the order option from "date.order":http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18 (unless you pass the option explicitely). All date selection helpers translate the prompt using the translations in the "datetime.prompts":http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L83 scope if applicable. * The +number_to_currency+, +number_with_precision+, +number_to_percentage+, +number_with_delimiter+, and +number_to_human_size+ helpers use the number format settings located in the "number":http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2 scope. h5. Active Record Methods * +human_name+ and +human_attribute_name+ use translations for model names and attribute names if available in the "activerecord.models":http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L43 scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes". * +ActiveRecord::Errors#generate_message+ (which is used by Active Record validations but may also be used manually) uses +human_name+ and +human_attribute_name+ (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes". *+ ActiveRecord::Errors#full_messages+ prepends the attribute name to the error message using a separator that will be looked up from "activerecord.errors.format.separator":http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91 (and which defaults to +' '+). h5. Active Support Methods * +Array#to_sentence+ uses format settings as given in the "support.array":http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L30 scope. h3. Customize your I18n Setup h4. Using Different Backends For several reasons the Simple backend shipped with Active Support only does the "simplest thing that could possibly work" _for Ruby on Rails_ [3] ... which means that it is only guaranteed to work for English and, as a side effect, languages that are very similar to English. Also, the simple backend is only capable of reading translations but can not dynamically store them to any format. That does not mean you're stuck with these limitations, though. The Ruby I18n gem makes it very easy to exchange the Simple backend implementation with something else that fits better for your needs. E.g. you could exchange it with Globalize's Static backend: <ruby> I18n.backend = Globalize::Backend::Static.new </ruby> h4. Using Different Exception Handlers The I18n API defines the following exceptions that will be raised by backends when the corresponding unexpected conditions occur: <ruby> MissingTranslationData # no translation was found for the requested key InvalidLocale # the locale set to I18n.locale is invalid (e.g. nil) InvalidPluralizationData # a count option was passed but the translation data is not suitable for pluralization MissingInterpolationArgument # the translation expects an interpolation argument that has not been passed ReservedInterpolationKey # the translation contains a reserved interpolation variable name (i.e. one of: scope, default) UnknownFileType # the backend does not know how to handle a file type that was added to I18n.load_path </ruby> The I18n API will catch all of these exceptions when they are thrown in the backend and pass them to the default_exception_handler method. This method will re-raise all exceptions except for +MissingTranslationData+ exceptions. When a +MissingTranslationData+ exception has been caught, it will return the exception’s error message string containing the missing key/scope. The reason for this is that during development you'd usually want your views to still render even though a translation is missing. In other contexts you might want to change this behaviour, though. E.g. the default exception handling does not allow to catch missing translations during automated tests easily. For this purpose a different exception handler can be specified. The specified exception handler must be a method on the I18n module: <ruby> module I18n def just_raise_that_exception(*args) raise args.first end end I18n.exception_handler = :just_raise_that_exception </ruby> This would re-raise all caught exceptions including +MissingTranslationData+. Another example where the default behaviour is less desirable is the Rails TranslationHelper which provides the method +#t+ (as well as +#translate+). When a +MissingTranslationData+ exception occurs in this context, the helper wraps the message into a span with the CSS class +translation_missing+. To do so, the helper forces +I18n#translate+ to raise exceptions no matter what exception handler is defined by setting the +:raise+ option: <ruby> I18n.t :foo, :raise => true # always re-raises exceptions from the backend </ruby> h3. Conclusion At this point you should have a good overview about how I18n support in Ruby on Rails works and are ready to start translating your project. If you find anything missing or wrong in this guide please file a ticket on "our issue tracker":http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview. If you want to discuss certain portions or have questions please sign up to our "mailinglist":http://groups.google.com/group/rails-i18n. h3. Contributing to Rails I18n I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first, and only then cherry-picking the best-of-bread of most widely useful features for inclusion in the core. Thus we encourage everybody to experiment with new ideas and features in plugins or other libraries and make them available to the community. (Don't forget to announce your work on our "mailing list":http://groups.google.com/group/rails-i18n!) If you find your own locale (language) missing from our "example translations data":http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale repository for Ruby on Rails, please "_fork_":http://github.com/guides/fork-a-project-and-submit-your-modifications the repository, add your data and send a "pull request":http://github.com/guides/pull-requests. h3. Resources * "rails-i18n.org":http://rails-i18n.org - Homepage of the rails-i18n project. You can find lots of useful resources on the "wiki":http://rails-i18n.org/wiki. * "rails-i18n Google group":http://groups.google.com/group/rails-i18n - The project's mailing list. * "Github: rails-i18n":http://github.com/svenfuchs/rails-i18n/tree/master - Code repository for the rails-i18n project. Most importantly you can find lots of "example translations":http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale for Rails that should work for your application in most cases. * "Lighthouse: rails-i18n":http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview - Issue tracker for the rails-i18n project. * "Github: i18n":http://github.com/svenfuchs/i18n/tree/master - Code repository for the i18n gem. * "Lighthouse: i18n":http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview - Issue tracker for the i18n gem. h3. Authors * "Sven Fuchs":http://www.workingwithrails.com/person/9963-sven-fuchs (initial author) * "Karel Minařík":http://www.workingwithrails.com/person/7476-karel-mina-k If you found this guide useful please consider recommending its authors on "workingwithrails":http://www.workingwithrails.com. h3. Footnotes fn1. Or, to quote "Wikipedia":http://en.wikipedia.org/wiki/Internationalization_and_localization: _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_ fn2. Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files. fn3. One of these reasons is that we don't want to imply any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions. h3. Changelog "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213/tickets/23
JUGEMテーマ:インターネット

RailsによるアジャイルWebアプリケーション開発 第3版

  • 2009.11.24 Tuesday
  • 01:20
Rails本の定番「RailsによるアジャイルWebアプリケーション開発」の、第3版が、2009年11月中に発売されるようです。
http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?&ISBN=978-4-274-06785-3

原本(英語版)は2009年3月発売で、Rails 2.2を対象に書かれています;


安定・最新版(現在:Rails2.3)との差が小さい内に、読んでおかないとですね。。。

ちなみに、11/24現在、amazonには書籍情報はありませんでした。

Rails 2.2、2.3 の i18n(国際化機能)のガイドを訳しちゅう...

  • 2009.11.12 Thursday
  • 21:33
 ひさびさに、Railsを使おうとしてます。前は、1.2とか使ってました。 いまはもう、2.3とかなんすね。。。 機能もいろいろ変わってるなー。と悪戦苦闘中です。

まずは、GetTextでやってたことを、標準化した、Rails 2.2、2.3 の i18n(国際化機能)を理解しようと思い;


にて、翻訳を作成中。 ミイラとりが、ミイラになっちゃいました。

途中から、よくわからんくなってきたので、誰か助けてー

手段と目的

  • 2009.10.20 Tuesday
  • 10:58
ここ最近、ふたたびケータイ向けサービスを作ろうと画策しています

前回チャレンジした際、ネックになったのが;

1). メールパーサー(携帯向け、デコメ含む)の実装
2). メールサーバ(MTA)の設定と、プログラム連携
3). 公開サーバの置き場所(ホスティング or DDNS+自宅サーバ)


1については、PHPを使ってやろうと決めて、3ヶ月間くらいPHPに慣れようと頑張っていました。ライブラリ組み合わせたり、cakePHP入れてサンプルアプリ作ったり。。。

でも、どうもやっぱりPHP好きになれない。ケータイ関連のライブラリやバッドノウハウの情報も豊富だから。素人プログラマーには適した言語だというのは理解したつもりだし。作りたいものが決まっているなら、PHPでやるのがいいんだろうなとは思うけど。でも楽しくない。気持ちよくない。 まずはサービスを世に出すことが先決だと考えて。なんとかPHPを好きになろうとしたんだけど。

でもダメ。美しくない。各プログラムの点と点が結びつかない感じ。線にならない。全体として、自分の頭の中に組み上がらない感じ。弘法筆を選ばず、なんだろうけど。俺は弘法さまじゃないし。嫌な思いしててはモチベーション続かないし。そもそも、弘法さまは、ホントに書きたい「書」を書くときには、筆を選びに選んでただろうし。

ってことで、やっぱりRuby On Railsでやろうと、初心に帰りました。前回の時に比べて、ライブラリも充実してきているし。情報も豊富になってきているし。まあ、どのバージョンを使うべきかとか、環境構築が大変。とかあるけど。どのみち「2」や「3」をクリアするには、レンタルサーバとかじゃあだめなわけだし。


ようやく、サーバ環境について、頭がまとまってきました。

なるべくお金かけずに。やりやすい環境つくろうっと♪

PR

calendar

S M T W T F S
   1234
567891011
12131415161718
19202122232425
2627282930  
<< November 2017 >>

本が出てます☆

Twitter

selected entries

categories

archives

recent comment

  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    通りすがり (01/19)
  • 携帯キャリアの、アクセス制限(未成年保護)についてのまとめ
    たけのこの里 (10/01)
  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    イシカワ (07/16)
  • さくらインターネットで、gem install すると「chown/chgrp: Operation not permitted 」と叱られる件の対応
    sean (04/20)
  • さくらインターネットで、gem install すると「chown/chgrp: Operation not permitted 」と叱られる件の対応
    てっちー (03/24)
  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    JO (01/04)
  • Passbook(パスブック)on iOS6 (NDAに触れない範囲で...)
    ぱん (09/28)
  • Passbook(パスブック)on iOS6 (NDAに触れない範囲で...)
    宮腰睦美 (09/23)
  • magit を、Lion の emacs にインストール
    ぱん (05/08)
  • 【 Xcode4.2 】Interface Builder使わずに、座標を合わせたい(習作1)
    ぱん (12/21)

recommend

iOSプログラミング 第2版
iOSプログラミング 第2版 (JUGEMレビュー »)
アーロン・ヒレガス,ジョー・コンウェイ,Aaron Hillegass,Joe Conway
■独学で初心者を脱出するには、必読ではないでしょうか。翻訳でニュアンスが伝わらない部分があるので、原書と、サポートサイト(英語)を活用すべし!です。

recommend

iPhoneプログラミングUIKit詳解リファレンス
iPhoneプログラミングUIKit詳解リファレンス (JUGEMレビュー »)
所 友太
■内容古いですが、iOSプログラマー中級以上の階段を登るために、必要な本だと思います。iOS5対応版出ないかな。。

recommend

iOSプログラミング入門 - Objective-C + Xcode 4で学ぶ、iOSアプリ開発の基礎
iOSプログラミング入門 - Objective-C + Xcode 4で学ぶ、iOSアプリ開発の基礎 (JUGEMレビュー »)
大津 真
■Ch.1「iOS プログラミングを始めるための基礎知識」でXcodeの概要を理解して、Ch.2「Objective-C の基礎知識」で、Objective-Cの考え方を理解できます。iOSプログラミングのキックオフにぴったり。

recommend

去年ルノアールで
去年ルノアールで (JUGEMレビュー »)
せきしろ
■ルノアールで妄想が爆発

recommend

RailsによるアジャイルWebアプリケーション開発 第4版
RailsによるアジャイルWebアプリケーション開発 第4版 (JUGEMレビュー »)
Sam Ruby,Dave Thomas,David Heinemeier Hansson
■Railsのバイブル第4版の日本語版が2011年末にリリース!サーバサイドで準備するAPIや、Webサイト関連のもろもろは、やっぱRailsでしょう。

links

profile

search this site.

others

mobile

qrcode

powered by

無料ブログ作成サービス JUGEM