さとやn Blog

試合はRuby,勝負はC#!

RubyOnRails

Ruby1.9.2 Rails2.3 でMySQLのencodingトラブル

Ruby1.9.2からは文字列がエンコード情報を持つようになったようなのですが、Railsでよく使用されるMySQLドライバーが未対応のためか、ActiveRecordで取得したデータの文字列はすべてASCII8として扱われてしまうようです。

こいつのせいでViewの方でエラーが多発してしまい、さて困った、、、。 調べてみると gem mysql2 がこのエンコード問題にも対応しているらしい。

早速インストールしてみる。

https://github.com/brianmario/mysql2

上記サイトのActiveRecordの項目を読んでみると、Rails3.1未満の場合はバージョン0.2系を使え、とのことなので、environment.rb に

config.gem "mysql2", :version => "0.2.11"
として、
rake gems:install
database.ymlの方も
development:
  adapter: mysql2
  database: hoge
  encoding: utf8
とすると無事にマルチバイト文字も扱えるようになりました。 にしてもRuby1.8系のソースを1.9に合わせるためには、大量のファイルの先頭にエンコードを示すマジックコメントを追記しなけれならない。他に方法ないのかな。

Rails3でActiveScaffold

ActiveScaffoldはいつになったらRails3に対応するのかなー? なんてずーっと思ってたら、とっくにForkされたプロジェクトがあって、そちらがRails3に対応してました。

https://github.com/vhochstein/active_scaffold

動作確認のため簡単なアプリを作ってみる。

#railsプロジェクトを作成
rails new active_scaffold_test
cd  active_scaffold_test
bundle install

#ActiveScaffoldプラグインをインストール
  rails plugin install git://github.com/vhochstein/active_scaffold.git -r 'rails-3.0'

#gemでインストールしたい場合は
gem "active_scaffold_vho" 

#ActiveScaffoldのセットアップ 
rails g active_scaffold_setup jquery  #標準のPrototypeを使いたい場合は最後のjqueryの指定は無し

#バンドとバンドメンバーを管理するようなものを作ってみる
rails g active_scaffolf BandGroup name:string
rails g active_scaffolf BandMember name:string instrument:name band_group:references
rake db:migrate

#サーバー実行
rails s

こんな感じでできます

Rails3でRaisl2.x風にコントローラに名前空間を付ける

Rails2.x の頃はよく管理系のページは
admin/users
とか
admin/products
みたいにコントローラに自由に名前空間をつけてやってたんだけど、
Rails3で同じことをやろうとしたらルーティングエラーで怒られる。

Routes.rbを開いてみると

namespace :admin do
  resources :products
end


みたいな書き方がのサンプルがある。
でもこれっていわゆるRESTFULな使い方しかできない。
Action名とか自由につけたい場合はどうすればいいのだろう?

名前空間なしで以前のRaisl2.xふうにする場合は、単純にデフォルトでコメントアウトされている
#match ':controller(/:action(/:id(.:format)))'
この行を復活させればよかったんだけど、じゃあ同様にこれを上記の書き方で名前空間でくくってやればいいのかな?

namespace :admin do
  match ':controller(/:action(/:id(.:format)))'
end


う〜ん、だめだ、、、。

で、結局

match ':controller(/:action(/:id(.:format)))', :controller => /admin\/[^\/]+/

正規表現で対応することに、、、。

他に方法ないのか?
っていうかRESTFulってそんなにいいもの?
いちいちカスタム命名したアクション追加するたびに
Routes.rbに記述加えるのってすごく面倒だと思うのは私だけなんでしょうか?
new,create,edit,update,destroy以外のアクションって欲しくなるとき多々あるんだけど。。。

なんかめんどーだー、、。 
本気でRailsやめてASP.Net MVC で作りたくなってきた。
 

Kindleに朝日・日経・読売の社説&コラムを自動配信

丁度2年くらい前にRubyを使って自分宛にメール配信するそんなスクリプトを作ったのですが、Kindle購入時に割り当てられた専用のメールアドレス宛に配信すればよくない? ってことでちょっと改修。
Kindleの場合はメールに添付ファイルとしてKindleに取り込むデータを送らなければならないので、そこだけちょっといじって、あとはcronで毎日7:10(※7:00だとたまに更新されてない場合がある)に起動するように設定。

新松戸〜亀有あたりまで時間潰せます、、、。

興味のある方は自作してみるといいと思います。
産経、毎日も対応しようかな、、、。 

 IMG_0481

Rails3で mongrel

なんかRails3にで、
rails server
ってやると、mongrelがインストールされているにも関わらず、webrickが起動する、、、。

調べてみたら、
Gemfile(またか、、、)に
gem 'mongrel'

とするだけでいいらしい。

3はなんか色々変わってるんだなー、、。 
 

Rails: postgresではまる rake aborted! libpq.so.5: cannot open shared object file

まず、
gem install pg 
でこける。

gem install pg -- --with-pg-config=/usr/local/pgsql/bin/pg_config

でインストールはできたけど、rake db:create しようとしたら、今度は表題のエラーが出る。

libpq.so.5
が見つからないと言っているようです。

でも
/usr/local/pgsql/lib
にはちゃんとある。
ってことは単にパスが通ってないだけか、、、。でも、だいぶ前に通してたはずなんだけどなー、、、、あ、あれは別のマシンか、、、。

.bash_profileとか .zshrcとかに

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib

でちゃんとできました。

どうもパス通し忘れでハマることが多い、、、。

Rails3 非Restfullなアクションを使用できるようにする

先日Rails3では routes.rbが下記のようになっていてRestfullな物しか呼べないようになっていますが、正直アクション名とか自由に使いたいので、コメント外して使えるようにしました。

  # This is a legacy wild controller route that's not recommended for RESTful applications.
  # Note: This route will make all actions in every controller accessible via GET requests.
  # match ':controller(/:action(/:id(.:format)))'

ただ、それだけの話しです、、、。

jQueryUIで超簡単にAutoCompleteを試してみる

久しぶりにjQueryUIのサイトを見てみたら、新機能としてAutoCompleteなるものが追加されていました。丁度仕事でも使いそうなので、やってみることに。
新規にRails3でプロジェクトを作成したばかりなのでとりあえず、mainという名前でデフォルトのコントローラを作る。
  #rails g controller main
  create  app/controllers/main_controller.rb
  invoke  erb
  create    app/views/main
  invoke  test_unit
  create    test/functional/main_controller_test.rb
  invoke  helper
  create    app/helpers/main_helper.rb
  invoke    test_unit
  create      test/unit/helpers/main_helper_test.rb
とりあえずサーバーを起動して main コントローラにアクセスしてみると、そんなページないよーってな感じでRouting Errorになる。 今までは何の問題もなくいけてたんだけどなー、、、Rals3からはいちいちルーティングファイルに書き込む必要があるのだろうか? 調べないとよくわからないので、とりあえず routes.rbをデフォルトのコントローラとアクションが main/index になるように変更。
  # You can have the root of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to => "welcome#index"
  root :to => "main#index"
でapp/views/main/index.html.erb には、jqueryUIのautocompleteのドキュメントに従ってこんな感じでサンプルを書いてみる。 とりあえずデータはJavaScript直書きで持たせてみる。
	<input type="text" id="textbox1"></input>
	<script type="text/javascript" charset="utf-8">
		$(function(){
			var dataItems = ["C#", "C++", "C", "Java", "JavaScript", "Ruby", "IronRuby", "JRuby"];

			$("#textbox1").autocomplete({
				source : dataItems
			});
		})
	</script>
ページを表示してみる。

45)

かなり簡単にできてしまいます。 でも、実際にはサーバーと通信させる場合のほうが多いと思います。 その場合は source オプションに JSONデータを返すURLを指定してあげて、サーバー側では、 文字列配列か、もしくは { label : '表示項目', value : 'Value値'}の配列を返すように実装してあげれば良いようです。
ユーザーが入力した文字は term というパラメータ名でサーバーに渡るので、そいつをキーワードとしてフィルタリングするような感じになるかと思われます。
DBをいちいち用意するのは面倒だったので、あらかじめ配列で持たせたプログラミング言語名称一覧からユーザーが入力した文字に該当するものをJSONで返すような処理を書いてみました。
	class MainController < ApplicationController
	  def index
			#なんかまたルーティングの設定なのか、上手く行かのいので indexアクションの中でajaxリクエストかどかで処理を分けてしまった、、、
	    if request.xhr?
	      data_items = %w(C# C++ C Java JavaScript Ruby IronRuby JRuby)
	      return render :json => data_items.find_all{|lang| lang.include?(params[:term]) }
	    end
	  end
	end
JavaScriptの方は sourceオプションをURLに変更するだけ。
	<input type="text" id="textbox1"></input>
	<script type="text/javascript" charset="utf-8">
		$(function(){
			//var dataItems = ["C#", "C++", "C", "Java", "JavaScript", "Ruby", "IronRuby", "JRuby"];
			$("#textbox1").autocomplete({
				//source : dataItems
				source : "/"
			});
		})
	</script>
う〜ん、なんて簡単なんだ、、、、。

31)

ハンドルされなかった例外をメール通知してくれるプラグイン Exception Notifier

そんなプラグインがあるそうです。
先日Rails本をKindleで読んでいたらそんな物があるよー、てなことが書いてありました。

以前は、rescue_action_in_public とかで独自に実装してたりしたのですが、今回は折角なのでプラグインを使うことにしよう。

https://github.com/rails/exception_notification
上記が最新版なのですが、私のRailsは2.3系なので、

http://github.com/rails/exception_notification/tree/2-3-stable
こっちからダウンロード。
なんか ./script/plugin install では上手くいかなかったので、
Downloadリンクからtar.gzファイルを落として直接
vendor/plugin/適当名前 に解凍しました。

READMEの基本的な使用方法を読んでみる。

== Usage

First, include the ExceptionNotifiable mixin in whichever controller you want
to generate error emails (typically ApplicationController):

  class ApplicationController < ActionController::Base
    include ExceptionNotification::Notifiable
    ...
  end

Then, specify the email recipients in your environment:

  ExceptionNotification::Notifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com)

And that's it! The defaults take care of the rest.


要はApplicationControllerの先頭で

    include ExceptionNotification::Notifiable

してやって、config/environment.rbでもconfig/initializers に適当なファイルを作ってそのなかで、

  ExceptionNotification::Notifier.exception_recipients = %w(送信先のメールアドレス)

ってしてあげればOKらしい。

あ、もちろんActionMailerが設定済みでメール送信できる環境にあることが前提ですが。
私の場合はGMailで送るのでActionMailerの設定はこんな感じになってます。


ActionMailer::Base.smtp_settings = {
  :enable_starttls_auto => true,
  :address => "smtp.gmail.com",
  :port => 587,
  :domain => "hogehoge",
  :authentication => :plain,
  :user_name => "Gmailアカウント",
  :password => "Gmailパスワード"
}  

で、早速わざと例外を投げるアクションを作ってメールが飛ぶかどうか実験してみる。

HogeController < ApplicationController 
  def index
    raise 'わざとエラー'
  end
end
う〜ん、とばない、、、。というかメール送信処理が呼ばれた形跡すらない、、、。
あ、developmentモードで起動してるからかな? とおもい、
./script/server -e production
で本番モードで実行してみる。

Net::SMTPFatalError (555 5.5.2 Syntax error. t14sm2087499icd.10
):
  /home/satoyan/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/1.8/net/smtp.rb:942:in `check_response'
  /home/satoyan/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/1.8/net/smtp.rb:911:in `getok'
  /home/satoyan/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/1.8/net/smtp.rb:826:in `mailfrom'
  /home/satoyan/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/1.8/net/smtp.rb:653:in `sendmail'
  /home/satoyan/.rvm/rubies/ruby-1.8.7-p330/lib/ruby/1.8/net/smtp.rb:526:in `start'

なんかこんなエラーがでてしまう。

調べてみるとNet::SMTPのライブラリに変更があったようで送信者に
senderName<hogehoge@hoge>
みたいな書き方をするとこのエラーになるようです。

で、送信者ってどうやって設定するのか調べたらこれもREADMEに書いてありました。

  # defaults to exception.notifier@default.com
  ExceptionNotification::Notifier.sender_address =
    %("Application Error" <app.error@myapp.com>)

やはり、デフォルトでダメのようです。
なので
 ExceptionNotification::Notifier.sender_address = 'hogehoge@hoge'
と書き換えて再度実行。

ちゃんとメールが飛びました。

で、メールにはどんな情報があるかというと、

By default, the notification email includes four parts: request, session,
environment, and backtrace (in that order).

とあるように、
  1. リクエスト情報
  2. セッション
  3. 環境変数
  4. 例外のスタック
の4つが取れようです。

ただし、これは app/views/exception_notifier  下に独自にビューを置くことでカスタマイズ可能、とのことです。

また、404エラーの場合は、メール通知はされないようです。
たしかに404でいちいちメール送信されたくはないです。

また、当然ながら、独自に例外をハンドルしている場合もメール通知はされません。
手動でメールを送信する場合は、こんな感じで notify_about_exception を呼び出せばOKのようです。

  def index
    #risky operation here
  rescue StandardError => error
    #custom error handling here
    notify_about_exception(error)
  end


ただ、別件でやってるRailsの方は、システムからメールを飛ばすこと自体できないんで、そっちでは使えねー、、。ていうかメール飛ばすくらい許可しろよって感じなんですが、、、。

Jrailsと同時にActiveScaffoldも使用する場合

RailsでPrototype.jsの代わりにjqueryを使うためのプラグインとしてJrailsというものがあり、非常に便利なのですが、ActiveScaffoldというこれまた非常に便利なプラグインを同時に使用しようとすると、ActiveScaffoldを適用したページ表示の際に、Prototype.jsが読み込まれてないですよー、といった感じで怒られてしまいます。
※ActiveScaffoldはScaffoldのAjax版みたいなものです。詳しくは
http://activescaffold.com/

実際Jrailsを使ってるので
<%= javascript_include_tag :defaults %>


ってやってもPrototype.jsではなくjQueryインクルードのタグが生成されます。

で、どうやるのかな? と調べたところ、
ちゃんとActiveScaffoldのWikiにありました。

Jrailsを適用したくない、というか、Prototype優先にしたいコントローラで、
  ActionView::Helpers::PrototypeHelper::JQUERY_VAR = 'jQuery'

のようにして、JavaScriptの$をjQueryで上書きさせない様にしてやります。


実際にJrailsのソースを見ると、

unless const_defined? :JQUERY_VAR
  JQUERY_VAR = '$'
end

といった記述があります。

ですので、別にjQueryという文字列でなくても良いわけで、jQueryのサイトにもあるように
var $j = jQuery.noConflict();
$j とかでも問題なし。


私の場合、ActiveScaffoldはAdmin系のページでしか使わないので、Admin系専用の基底コントローラクラスを作って、他のAdmin系コントローラはそいつを継承させるようにしてるため、こんな感じで対応してあげればOKでした。
class Admin::AdminControllerBase < ApplicationController
  ActionView::Helpers::PrototypeHelper::JQUERY_VAR = 'jQuery'
  layout 'admin'
  before_filter :block_none_admin
  ActiveScaffold.set_defaults do |config|
    config.ignore_columns.add [:created_at, :updated_at]
  end
end

adminというlayoutを使っているので、そいつの中もこんな感じに jQuery.noConflict してやってPrototypeを読み込んであげればOKです。
effects スクリプトも指定するのも忘れないようにましょう。

<%= javascript_include_tag :defaults %>
		
<%= javascript_include_tag "prototype", "effects"  %> 
<%= active_scaffold_includes %>

あ、でもページングでエラーになる、、。 もうちょっと調べないと駄目だ、、、。
livedoor プロフィール
QRコード
QRコード
  • ライブドアブログ