さとやn Blog

試合はRuby,勝負はC#!

2011年02月

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)

Rails3でjQueryを規定のクライアントサイドのスクリプトとして使う

仕事ではまだRails3はやったことないのですが、そんな事言っているといつまでたっても触る機会もなさそうなので、ちょっとしたJavaScriptなんかを試したい時用のプロジェクトをRails3で一個作っておこうと思いやってみました。
とりあえず、Rails3をインストール。
gem install rails
ちょこっとしたJavaScriptとかを試したい時用のプロジェクトなので、 js_spikeって名前でプロジェクトを作ってみる。
rails new js_spike
public/javascripts下を覗いてみるとデフォルトでは例によってPrototypeになっているようです。
-rw-rw-r-- 1 satoyan satoyan    148 Feb 28 15:52 application.js
-rw-rw-r-- 1 satoyan satoyan  34787 Feb 28 15:52 controls.js
-rw-rw-r-- 1 satoyan satoyan  31056 Feb 28 15:52 dragdrop.js
-rw-rw-r-- 1 satoyan satoyan  38467 Feb 28 15:52 effects.js
-rw-rw-r-- 1 satoyan satoyan 162353 Feb 28 15:52 prototype.js
-rw-rw-r-- 1 satoyan satoyan   6278 Feb 28 15:52 rails.js
jquery-railsというgemを入れるとクライアントサイドのスクリプトをすべてjQueryのものに置き換えてくれるようなのでそれをインストールしてみる。 Gemfileに 下の一行を追加。
	gem 'jquery-rails'
bunldle install を実行
	#bundle install を実行
	
	Fetching source index for http://rubygems.org/
	Using rake (0.8.7) 
	Using abstract (1.0.0) 
	Using activesupport (3.0.5) 
	Using builder (2.1.2) 
	Using i18n (0.5.0) 
	Using activemodel (3.0.5) 
	Using erubis (2.6.6) 
	Using rack (1.2.1) 
	Using rack-mount (0.6.13) 
	Using rack-test (0.5.7) 
	Using tzinfo (0.3.24) 
	Using actionpack (3.0.5) 
	Using mime-types (1.16) 
	Using polyglot (0.3.1) 
	Using treetop (1.4.9) 
	Using mail (2.2.15) 
	Using actionmailer (3.0.5) 
	Using arel (2.0.9) 
	Using activerecord (3.0.5) 
	Using activeresource (3.0.5) 
	Using bundler (1.0.10) 
	Using thor (0.14.6) 
	Using railties (3.0.5) 
	Using rails (3.0.5) 
	Installing jquery-rails (0.2.7)  #インストールされました...
	Using sqlite3 (1.3.3) 
"rails g" でgenerator一覧を見てみると新たにjQueryの欄ができています。
	#rails g でgeneratorのヘルプを見てみる
	
	Usage: rails generate GENERATOR [args] [options]

	General options:
	  -h, [--help]     # Print generator's options and usage
	  -p, [--pretend]  # Run but do not make any changes
	  -f, [--force]    # Overwrite files that already exist
	  -s, [--skip]     # Skip files that already exist
	  -q, [--quiet]    # Suppress status output

	Please choose a generator below.

	Rails:
	  controller
	  generator
	  helper
	  integration_test
	  mailer
	  migration
	  model
	  observer
	  performance_test
	  plugin
	  resource
	  scaffold
	  scaffold_controller
	  session_migration
	  stylesheets

	Jquery:
	  jquery:install
	
使い方を jquery:install で表示してみる。
	#rails g jquery:install --help
	
	Usage:
	  rails generate jquery:install [options]

	Options:
	  [--version=VERSION]  # Which version of jQuery to fetch
	                       # Default: 1.5
	  [--ui]               # Include jQueryUI

	Runtime options:
	  -s, [--skip]     # Skip files that already exist
	  -p, [--pretend]  # Run but do not make any changes
	  -q, [--quiet]    # Supress status output
	  -f, [--force]    # Overwrite files that already exist

	This generator downloads and installs jQuery, jQuery-ujs HEAD, and (optionally) the newest jQuery UI
	
バージョンの指定とjQueruyUIを使うかどうかの指定ができるらしいので、さっそく実行してみる。
	#rails g jquery:install --ui --force
	
    remove  public/javascripts/controls.js
    remove  public/javascripts/dragdrop.js
    remove  public/javascripts/effects.js
    remove  public/javascripts/prototype.js
  fetching  jQuery (1.5)
    create  public/javascripts/jquery.js
    create  public/javascripts/jquery.min.js
  fetching  jQuery UI (latest 1.x release)
    create  public/javascripts/jquery-ui.js
    create  public/javascripts/jquery-ui.min.js
  fetching  jQuery UJS adapter (github HEAD)
     force  public/javascripts/rails.js
	
public/javascripts下を覗いてみると、jquery関連のファイルが生成されていました。
  # ll public/javascripts
	-rw-rw-r-- 1 satoyan satoyan    148 Feb 28 16:25 application.js
	-rw-rw-r-- 1 satoyan satoyan 216840 Feb 28 16:40 jquery.js
	-rw-rw-r-- 1 satoyan satoyan  85260 Feb 28 16:40 jquery.min.js
	-rw-rw-r-- 1 satoyan satoyan 367486 Feb 28 16:40 jquery-ui.js
	-rw-rw-r-- 1 satoyan satoyan 198792 Feb 28 16:40 jquery-ui.min.js
	-rw-rw-r-- 1 satoyan satoyan   5033 Feb 28 16:40 rails.js
でもpublic/stylesheets下にはjQueryUI用のCSSはできてないようです。 あれもなきゃだめじゃん、と言うことでCSSはGoogleCDNを利用することにします。 とりえあず redmondというテーマのものを使うようにapplicataion.html.erbに書きこんでおく。
	  <%= stylesheet_link_tag :all %>
	  <%= javascript_include_tag :defaults %>
	  <%= csrf_meta_tag %>
		<%= stylesheet_link_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/themes/redmond/jquery-ui.css" %>
とりあえず、こんな感じでjQueryの設定はできました。CSSもやってくれないと不便なような気がするんだけどなー、、、、。
使い方知らないだけ?

ハンドルされなかった例外をメール通知してくれるプラグイン 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 %>

あ、でもページングでエラーになる、、。 もうちょっと調べないと駄目だ、、、。

MonoDevelop(Mac版)でスクリプトエラー

先日MonoDevelopをアップデートして、プログラムを実行しようとcomand + R を押したら、こんなエラーが出た。
01)


普通にビルドしてターミナルから
mono 実行ファイル 
ってやれば問題なく動くので、単にIDEの問題なのかと思い、設定とか見てたら、どうも プロジェクトのオプションで

Run on external console 

を無効にすればいいらしい。
23)


このオプションがいつからあったのかも知らないし、なぜデフォルトで有効になっているのかはわかりませんが、とにかく外せば今まで通りにcommand + R で即実行することができる。
そもそも外部コンソールってここでは何を指してるんだろう?
IDE内部のものではなくターミナルとかが使えるってことなのかな? よくわかりません。


MonoDevelopでapp.config

.netアプリのアプリケーションの設定ファイルはデフォルトでは
実行ファイル名.config 
という名前になるのですが、通常はVisualStudioではApp.configというファイルを編集して、ビルドするとは出力先にリネームされて、hoge.exe.config みたいな感じにしてくれます。

で、MonoDevelop(マック版)ではどうやるんだろう?

ファイルの新規作成ダイアログにそれっぽいものがあります。

30)

とりあえず名前をApp.config にして適当に設定をかいてビルドしてみましたが、出力先には実行ファイルしか生成されず、、、、。

IDEでファイルのプロパティを見てみると、それっぽい設定を発見。
55)

BuildAction: ApplicationDefinition
Copty to output directory: Always copy | Copy if newer

にして、もう一度ビルドすると、ちゃんと
実行ファイル名.config というファイルが生成されて無事に設定も読み込めました。
 

mono C# で gmail送信

XmlWebService(って今時言わないのかな)を叩いてその結果を見て正常なのかエラーなのかを携帯にメールで通知したくなったので、仕事ではRubyとかJavaばっかりなので、C#で作ってみました。
cronで動かすので、当然monoのC#です。
static void sendMail (string message, string subject)
{
		var smtp = new SmtpClient ("smtp.gmail.com", 587);
		smtp.EnableSsl = true;

		//ユーザー名は@gmail.comは含めない
		smtp.Credentials = new NetworkCredential ("gmailAccount", "password");
		ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
		
		var msg = new MailMessage ();
		msg.Body = message;
		msg.Subject = subject;
		msg.To.Add ("hoge@hoge"); 
		msg.From = new MailAddress ("hoge2@hoge");
		smtp.Send (msg);

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
これがないと、
System.Net.Mail.SmtpException: Message could not be sent. ---> System.IO.IOException: The authentication or decryption has failed. ---> System.InvalidOperationException: SSL authentication error: RemoteCertificateNotAvailable, RemoteCertificateChainErrors
と怒られてしまいます。
本当はエラーとかチェックするんでしょうけど、とりあえずここでは、trueを返して問題なしですよー、としてます。
これについては、
http://www.atmarkit.co.jp/fdotnet/dotnettips/867sslavoidverify/sslavoidverify.html
が分かりやすく解説してあります。

Rails: fixture:loadでno(ナンバーの意)という列名に注意

Railsで

rake db:fixtures:load

を実行したら

PGError: ERROR: column "false" of relation xxxxx云々

そもそも"false" なんていうカラムはないんだけど、、、。

で、Fixtureの中身を確認してみたら
no(ナンバーという意味でそういう名前にしたのかと思われます)という列名を発見!
※fixutureはこんな感じ。

id: 1
name: satoyan
no: 
job: 
....

こいつが悪さをしていたようです。
使ってるDBはPostgresqlなのですが、boolean型のカラムに対して、no, 0, false, fというリテラルは false の意になるようで、どうもRailsの方でnoという文字列を列名なのにも関わらず勝手にfalseという文字に置き換えてくれてしまったようです。

と言うことで no あらため "no" とすることで解決。
最初、「はぁ?  falseなんて列あるわけねーだろ、、」とか言ってしばらく混乱してしまいました。


Javaでエクセルファイルを読んでみる POIってなんだ?

最近Javaでエクセルファイルをを扱う必要が出てきて、聞いたところによるとPOIというものを使うらしい。
POIは100%Javaで書かれたマイクロソフト製品で作成されたドキュメントを扱うライブラリだそうで、POIという名前には2重の意味が込められているそうです。
詳しくは下記のサイトで。


で、早速最新版の3.7をダウンロード。


Eclipseで新規プロジェクトを作成して、POIライブラリをビルドパスに追加。
05)

サンプル用のエクセルファイルを作成。
55)

ファイル形式はXML形式ではなく旧式の(というか今でも最も一般的な気がする)xlsで保存。
※POI自体は両方のフォーマットに対応しているようです。
59)

クイックガイドを参考にコードを書いてみる。
かなり直感的に扱えるようです。
    1 import java.io.FileInputStream;
2 import java.io.InputStream;
3 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
4 import org.apache.poi.ss.usermodel.Row;
5 import org.apache.poi.ss.usermodel.Sheet;
6 import org.apache.poi.ss.usermodel.Workbook;
7
8
9 public class Main {
10 public static void main(String[] args){
11 try {
12 InputStream file = new FileInputStream("data/hello_poi.xls");
13 Workbook book = new HSSFWorkbook(file);
14 Sheet sheet = book.getSheetAt(0);
15 for(int rowIndex = 0; rowIndex < 2; rowIndex++) {
16 Row row = sheet.getRow(rowIndex);
17 System.out.printf("%s, %s\n", row.getCell(0), row.getCell(1));
18 }
19 file.close();
20 } catch (Exception e) {
21 e.printStackTrace();
22 }
23
}

24 }

25

実行するとちゃんと表示できました。
18)

次は書き出す処理をやってみる。



livedoor プロフィール
QRコード
QRコード
  • ライブドアブログ