GOL @Wiki
Rubyメモ
最終更新:
divadiva
-
view
Ruby関連の備忘録です。
- rakeを使おうとすると"Could not find a JavaScript runtime"とかいいやがる
- RoRでAjaxとthickboxを連携する
- Windows環境でgemをインストールするときにRubyのコンパイル環境を要求される
- データベースの設定
- Rails2.0でin_place_editorを使うと、InvalidAuthenticityTokenが発生する
- RoR2.3.2でgettextする
- インプレースエディタの選択リスト版を実装する
- ページネーション・プラグインをインストールする
- インプレースエディタを拡張する
- RailsアプリでREST通信する場合にInvalidAuthenticityTokenが出る
rakeを使おうとすると"Could not find a JavaScript runtime"とかいいやがる
「JavaScriptのランタイムが無いよ」の解決策は、一般的には、libv8、therubyracer、execjsのgemをインストールしましょう、です。
しかし、
しかし、
$ bundle exec gem list
したらちゃんと表示されていて、どう考えてもtherubyracer等のJavaScriptランタイムはインストールされているのに、エラーが出る、という事態が発生することがあります。
これは、インストールされていないのではなくて、実行時エラーを発生していることが問題の現認である場合があります。次のコマンドを試してみましょう。
$ ruby -e "require 'execjs'"
autodetectメソッドがエラーを返していますか?(それを前提に話を進めます)
execjs/runtimes.rbのautodetectメソッドを見てみます。
EXECJS_RUNTIME環境変数で指定されているランタイムか、あるいは適当に利用可能なランタイムを探しています。therubyracerがインストールされているはずなのにbest_availableメソッドがfalseを返しているのでしょうか?調べてみましょう。
RubyRacerRuntimeクラスのavailable?メソッドです(ruby_racer_runtime.rb)。
execjs/runtimes.rbのautodetectメソッドを見てみます。
EXECJS_RUNTIME環境変数で指定されているランタイムか、あるいは適当に利用可能なランタイムを探しています。therubyracerがインストールされているはずなのにbest_availableメソッドがfalseを返しているのでしょうか?調べてみましょう。
RubyRacerRuntimeクラスのavailable?メソッドです(ruby_racer_runtime.rb)。
def available? require "v8" true rescue LoadError false end end
v8ライブラリのロードに失敗しているのでしょうか?調べてみます。
$ ruby -e "require 'v8'"
cannot restore segment prot after reloc: Permission deniedとかエラーを吐いています。これについて調べるとわかることですが、どうやらSELinuxが邪魔をしているようです。
てことで、SELinuxが動作しているようであれば、停止しましょう。これで解決されるはずです。
※このサイトのブログが参考(ていうかそのまま)になりました。ありがとうございました!
※このサイトのブログが参考(ていうかそのまま)になりました。ありがとうございました!
Windows環境でgemをインストールするときにRubyのコンパイル環境を要求される
たとえばPostgreSQLサーバへの接続アダプタであるpgパッケージをインストールする場合などがこのケースにあたります。コンパイル自体はgemのinstallコマンドで自動事項されるのですが、コンパイル環境だけは事前に整えておく必要があります。
UNIX系はともかく、Windowsの場合コンパイラの入手、準備などが慣れてないとよくわかりません。が、丁寧に解説してくれているサイトがありました。
コンパイラが準備できても、Ruby自体のヘッダファイルがないとコンパイルはできません。ActiveScriptRubyをインストールした場合、ヘッダファイルはインストールされていません。この場合、このサイトからASRDev18.msiをダウンロードしてインストール実行すればOKです。開発環境に必要なものが追加インストールできます。その際インストール先はActiveScriptRubyと同じにしておけばよいでしょう。
ちなみに、Visual C++ 2008 Express Editionを使用する場合、Rubyのconfig.hを書き換える必要があることはこのサイトでも解説されていますが、ASRDev18.msiを使用してヘッダ類をインストールした場合、config.hは <RUBY-INST-DIR>\lib\ruby\<VERSION>\i386-mswin32 にあります。
データベースの設定
PostgreSQL関連
PostgreSQLのドライバはたくさん乱立していますが、ruby-pgをインストールすることにより接続できます。(もちろん他のgemでもいいですが)
pgをgem installすると、pg.soというライブラリがインストールされますが、ただ require 'pg' しただけでは、LoadError が発生し、ライブラリがないよ、といわれることがあります。これは単に pg.so の置き場所がRubyのライブラリロードパスに入ってないからです。
pgをgem installすると、pg.soというライブラリがインストールされますが、ただ require 'pg' しただけでは、LoadError が発生し、ライブラリがないよ、といわれることがあります。これは単に pg.so の置き場所がRubyのライブラリロードパスに入ってないからです。
ruby -e 'puts $:'
で現在のロードパスを確認してください。
その中に pg.so の置き場所がなければロードできません。ロードパスの変更は、環境変数RUBYLIBを設定すればOKです。あるいは、コマンドラインからの起動時に「-I<pg.soの置き場所>」と指定することも可能です。
その中に pg.so の置き場所がなければロードできません。ロードパスの変更は、環境変数RUBYLIBを設定すればOKです。あるいは、コマンドラインからの起動時に「-I<pg.soの置き場所>」と指定することも可能です。
ちなみに、このあたりのパスを通す仕組みはrubygemsに装備されているので、先に、
require 'rubygems'
してしまえば、このようなLoadErrorは無くなります。
また、Windowsの場合、pg.soが呼ばれるようになっても、libpq.dll が無いとまたもやエラーとなりますので、PostgreSQLのlibpq.dllの場所を環境変数PATHに加えておきましょう。
それでも、msvcr90.dll が無い、というエラーが出ることもあります。この場合、Rubyの
それでも、msvcr90.dll が無い、というエラーが出ることもあります。この場合、Rubyの
<Rubyインストールディレクトリ>\1.8\lib\ruby\1.8\i386-mswin32\rbconfig.rb
の、
CFLAGS: -MD
という箇所を -MT に修正して、再度 pg のインストールをすればOKです。
また、Solaris10やOpenSolarisでpgをインストールする際、/usr/ucb/installを要求されるかもしれません。この場合、
ln -s /usr/bin/ginstall /usr/ucb/install
でソフトリンクを作って解決しちゃいましょう。
MySQL関連
MySQLがデフォルトと異なるインストール設定がなされている場合、Rubyから接続できない場合があります。たとえば、ソケットファイル名がデフォルトと異なる場合や、デフォルトと異なる場所に存在する場合は、下記のようにdatabase.ymlに書き加えてください。
socket: /foo/bar/filename.sock
Rails2.0でin_place_editorを使うと、InvalidAuthenticityTokenが発生する
Rails2.0になってから、インプレースエディタなどが含まれているScript.aculo.usはコアモジュールから外されました。
ですので、外部プラグインとしてインストールするわけですが、いざ使おうとすると、データベース更新の段になって、InvalidAuthenticityTokenエラーが発生します。これはRails2.0になってからセキュリティが高められ、デフォルトでCSRF対策がなされているからですが、おかげでAjaxでデータベースに更新をかけるような操作(in_place_editorによる更新など)を行うと上記のようなエラーが発生してしまうわけです。
この解決法としてin_place_editorによる更新操作をセキュリティの対象外にしてしまうという安直な方法がネット上にころがっていたりしますが、それではセキュリティ的に問題ですので、このページにin_place_editorにパッチを当てる方法で解決しましょう。このページにも書いてありますが、パッチはここです。
ですので、外部プラグインとしてインストールするわけですが、いざ使おうとすると、データベース更新の段になって、InvalidAuthenticityTokenエラーが発生します。これはRails2.0になってからセキュリティが高められ、デフォルトでCSRF対策がなされているからですが、おかげでAjaxでデータベースに更新をかけるような操作(in_place_editorによる更新など)を行うと上記のようなエラーが発生してしまうわけです。
この解決法としてin_place_editorによる更新操作をセキュリティの対象外にしてしまうという安直な方法がネット上にころがっていたりしますが、それではセキュリティ的に問題ですので、このページにin_place_editorにパッチを当てる方法で解決しましょう。このページにも書いてありますが、パッチはここです。
RoR2.3.2でgettextする
やり方はこのページを見てください。
、、、だけだと何なので、ちょっと捕捉しますと。
まずは、上記にしたがって、各種ファイルをロケール対応に書き換えていってください。もしvalidateが発する標準のエラーメッセージの日本語化だけが目的ですと、実際には特に何もする必要はありません。最初の設定をするだけでテーブルの列名以外は勝手に日本語化メッセージが表示されるようになります。
Rakefileについてですが、ユーザ独自のRakeタスクを標準のタスクに追加したい場合、<RAILS_HOME>/lib/tasks 以下に、*.rake ファイルを作成し、上記URLにしたがってRakeタスクを記述して下さい。この際、ネームスペースを使用すると、よりいいでしょう。
Rakefileについてですが、ユーザ独自のRakeタスクを標準のタスクに追加したい場合、<RAILS_HOME>/lib/tasks 以下に、*.rake ファイルを作成し、上記URLにしたがってRakeタスクを記述して下さい。この際、ネームスペースを使用すると、よりいいでしょう。
namespace :aaa do namespace :bbb do desc '説明' task :タスク名 do 実際の処理内容 end end end
と記述すると、「aaa:bbb:タスク名」みたいに標準タスクっぽい感じで呼び出せます。
「*.pot」ファイルを生成するタスク(上記URLでは rake updatepo)を実行したあと「*.pot」ファイルに日本語リソースを記述し、「*.po」ファイルを作成します。そしてまたRakeタスクで GetText.create_mofiles して、「*.po」ファイルから「*.mo」ファイルを生成します。
ちなみに「*.pot」ファイルをコピーして日本語リソースの元ファイルを作成する際に拡張子を「pot」のままで作成したために、GetText.create_mofiles がまったく機能せず、小一時間ばかり時間を無駄にしてしまったのはここだけの秘密です。。
「*.pot」ファイルを生成するタスク(上記URLでは rake updatepo)を実行したあと「*.pot」ファイルに日本語リソースを記述し、「*.po」ファイルを作成します。そしてまたRakeタスクで GetText.create_mofiles して、「*.po」ファイルから「*.mo」ファイルを生成します。
ちなみに「*.pot」ファイルをコピーして日本語リソースの元ファイルを作成する際に拡張子を「pot」のままで作成したために、GetText.create_mofiles がまったく機能せず、小一時間ばかり時間を無駄にしてしまったのはここだけの秘密です。。
ページネーション・プラグインをインストールする
一般に推奨されるインストール方法は、
gem sources -a http://gems.github.com gem install mislav-will_paginate
ですが、
ここからtarballとしてダウンロードしてファイル展開でもよし。
ここからtarballとしてダウンロードしてファイル展開でもよし。
インプレースエディタを拡張する
※Rails2.0以降の外部プラグイン版in_place_editingの使用を前提とします。
私がインプレースエディタを使用して感じる大きな不満点は下記の2点です。
私がインプレースエディタを使用して感じる大きな不満点は下記の2点です。
- データが空の場合編集モードにする手段がない
- モデルのバリデーションチェック機能が利用できない
一つ目については、lib/in_place_macros_helper.rb を改造することで対処しました。データがないと代わりに「N/A」を表示します。この「N/A」をクリックすることで編集モードに移行します。
具体的には、in_place_editor_fieldメソッドを書き換えています。
具体的には、in_place_editor_fieldメソッドを書き換えています。
def in_place_editor_field(object, method, tag_options = {}, in_place_editor_options = {}) tag = ::ActionView::Helpers::InstanceTag.new(object, method, self) tag_options = {:tag => "span", :id => "#{object}_#{method}_#{tag.object.id}_in_place_editor", :class => "in_place_editor_field"}.merge!(tag_options) in_place_editor_options[:url] = in_place_editor_options[:url] || url_for({ :action => "set_#{object}_#{method}", :id => tag.object.id }) # 改造した。データがない場合、「N/A」をデフォルト値にする。 tag_string = tag.to_content_tag(tag_options.delete(:tag), tag_options) re = /(<span.*>)(.*)(<\/span>)/ md = re.match(tag_string) if md[2] == '' tag_string = sprintf("%sN/A%s", md[1], md[3]) end tag_string + in_place_editor(tag_options[:id], in_place_editor_options) end
RailsアプリでREST通信する場合にInvalidAuthenticityTokenが出る
RailsアプリでRESTfulな作りにしていて、かつ、JavaScriptで直接HTTPRequest通信部を手書きにすることがあると思います。
たとえばクライアント側でYahooのYUIなどのAjaxコンポーネントを使っている場合は、REST通信はYAHOO.util.Connect.asyncRequest()で実現するわけです。
この際、GETではなくてPOSTなどサーバ側の状態変更を伴う操作を要求すると、RailsのCSRF対策機能が働いてしまい「authenticity tokenが無い!」という例外を発生してしまいます。
たとえばクライアント側でYahooのYUIなどのAjaxコンポーネントを使っている場合は、REST通信はYAHOO.util.Connect.asyncRequest()で実現するわけです。
この際、GETではなくてPOSTなどサーバ側の状態変更を伴う操作を要求すると、RailsのCSRF対策機能が働いてしまい「authenticity tokenが無い!」という例外を発生してしまいます。
Railsの世界だけで作っている場合はCSRF対策など「裏方」処理を自動でやってくれるために気にすることはありませんが、別の仕組みを組み合わせた瞬間に、自分でめんどうをみなければなりません。
POSTの場合はURLパラメタとして「authenticity_token=<Railsが生成したCDRFトークン>」を付加する必要があります。
実際の方法は、まずホームページを出力する *.html.erbにて、
<%= hidden_field_tag 'authenticity_token', ERB::Util.url_encode(form_authenticity_token) %>
を埋め込み、CSRFトークンをHiddenフィールドとしてクライアントに送信しておきます。
そしてクライアント側で動くJavaScriptにて、
"authenticity_token=" + uriEncodedCsrfElem.value
をURLパラメータとして付加送信させます。
ちなみに、ERB::Util.url_encode()の使用は必須です。JavaScriptのencodeURI()ですと、たとえば「+」をエンコーディングしてくれないため、受け取ったRails側でプラスを半角スペースにデコードしてしまい、結果的にトークン内容に食い違いが発生し、やはり例外が発生してしまいます。
ですので、クライアントに送る段階で先にURIエンコーディングしてしまうのです。
ですので、クライアントに送る段階で先にURIエンコーディングしてしまうのです。