「RailsによるアジャイルWebアプリケーション開発」23章読了
Web2.0と題して、Prototype、Script.aculo.us、RJSテンプレートが取り上げられています。
Ajaxでdiv要素の更新
ページ中のpタグで囲ったところだけ、Ajaxで更新するというサンプルです。
ここでは、四つの方法で実現してみました。
- ハイパーリンクをクリックすると更新される
- フォームボタンをクリックすると更新される
- divで括られたテキストをクリックすると更新される(イベントハンドラ)
- 5秒置きに自動的に更新される(疑似プッシュ技術的な)
さっそく解説をば。
まずは、prototype.jsが必要になるので、JavaScriptライブラリの取り込みを行うため、レイアウトファイルを修正します。
app/views/layouts/products.html.erb
<head> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <title>Products: <%= controller.action_name %></title> <%= stylesheet_link_tag 'scaffold' %> <!-- add --> <%= javascript_include_tag :defaults %> </head>
headタグ内に追加しました。
:defaultsにすると、Prototype、Script.aculo.us、application.jsが取り込まれますが、個別に取り込むことも可能です。
次にコントローラ。
app/controllers/products_controller.rb
def ajaxtest end def ajaxtest_partial @dateTime = Time.now render(:partial => 'ajaxtest') end
Ajaxテスト用ページを表示するアクションajaxtestと、Ajaxリクエストに対してレスポンスを返すajaxtest_partialのアクションを定義しました。
次にビュー。
まずは、Ajaxレスポンスを描画するビューを作ります。
app/views/products/_ajaxtest.html.erb
<%= @dateTime %>
コントローラで取得した日時を、ただ表示しているだけですね。
次に、Ajaxレスポンスを取り込む本体のビューです。
app/views/products/ajaxtest.html.erb
<h3>Ajaxのテスト</h3> <!-- ajaxリクエストを行うハイパーリンク --> <%= link_to_remote "日時を更新リンク", :url => {:action => :ajaxtest_partial}, :update => 'datetime1' %> <!-- ajaxリクエストを行うフォームボタン --> <% form_remote_tag :url => {:action => :ajaxtest_partial}, :update => 'datetime1' do %> <%= submit_tag "日時を更新ボタン" %> <% end %> <!-- ajaxリクエストを行うHTML要素 --> <div onclick = "<%= remote_function(:update => 'datetime1', :url => {:action => :ajaxtest_partial}) %>"> 日時を更新テキスト(クリックしてね) </div> <!-- n秒置きに自動更新 --> <%= periodically_call_remote :url => {:action => :ajaxtest_partial}, :update => 'datetime1', :frequency => 5 %> <p id='datetime1'/>
ちと長いですが、冒頭で書いた4つの部分に分かれていることが分かれば、理解は容易かと思います。
でもって、
http://localhost:3000/products/ajaxtest/1
へアクセス。
すると、こんなページが表示されます。
どれかをクリック or 5秒間待つことで、ページ下部に現在の日時が表示されます。
簡単にできちゃいますね。
オートコンプリート
Google Suggest(http://www.google.com/webhp?hl=ja&complete=1)的な検索ボックスが実現できる機能らしいです。
とりあえずRails2.xではプラグインになったようなので、プラグインをインストールしてみる。
taka@taka-desktop:~/test$ ruby script/plugin install auto_complete + ./README + ./Rakefile + ./init.rb + ./lib/auto_complete.rb + ./lib/auto_complete_macros_helper.rb + ./test/auto_complete_test.rb
で、書籍の内容は役たたずになったようなので、このインストールされたREADMEを参考にコントローラとビューを作ってみる。
まずは、コントローラ。
app/controllers/products_controller.rb
auto_complete_for :post, :autocomplete_favorite_language def autocomplete_demo end def auto_complete_for_post_user_favorite_language puts(params[:post][:user_favorite_language]) render(:text=>'<ul><li>Ruby</li><li>Java</li><li>Haskell</li><li>C#</li></ul>') end
テキストフィールドに入れられた内容は、params[:post][:user_favorite_language]で取得できますが、
ここでは簡略のため、固定のリストを返すようにしています。
次にビュー。
app/views/products/autocomplete_demo.html.erb
<p><label for="user_favorite_language">お気に入りの言語</label><br/> <%= text_field_with_auto_complete :post, :user_favorite_language %>
text_field_with_auto_completeでオートコンプリート用テキストフィールドを生成しています。
で、
http://localhost:3000/products/autocomplete_demo/1
にアクセス。
と、NoMethodErrorで怒られる。
しばらく悩んだのち、
http://koress.jp/2007/08/ruby_on_rails.html
のサイトで、WEBrickを再起動する必要があることを知りました。。
で、再起動でとりあえずNoMethodErrorは解決。
次に、フォームが表示されたものの、
一向にオートコンプリートされない。
POSTだからダメなのかと思い、GETにしてみても同じくダメ。
試しにPOSTで直接アクセスしてみたらどうなるのかと思い、
こんなHTMLを書いてみることに。
public/test.html
<html> <form method="POST" action="/products/auto_complete_for_post_user_favorite_langu age"> <input type = "submit" value = "push"> </form>
で、http://localhost:3000/test.htmlにアクセスし、pushボタンをクリック。
すると、
ActionController::InvalidAuthenticityToken in ProductsController#auto_complete_for_post_user_favorite_language
が出てました。
これは、
http://brass.to/blog/rails_2_0_auto_complete.html
でも書かれている問題で、このページからリンクされている、
http://d.hatena.ne.jp/jakei/20080305/1204764230
のサイトのパッチを当てることで回避できました。(念のためWEBrickは再起動)
ちなみにですが、WEBrickのコンソールログにステータスコード422ってのが表示されてて、
なんだろうと思ってHTTP/1.1の仕様(RFC2616; http://www.ietf.org/rfc/rfc2616.txt)を見たのですが載ってませんでした。
これはWebDAVのために拡張されたもので、
RFC4918; http://www.ietf.org/rfc/rfc4918.txt
の11.2章に載ってますね。
「RailsによるアジャイルWebアプリケーション開発」24章読了
Action Mailerのお話し。
とりあえずメールを送ってみる。
サンプルとして、SMTPによるメール送信を試みる。
サーバはこういう時に僕がいつも使っているJamesを利用。(Jamesの設定は割愛します。どこかに載ってますので。)
まずは、SMTPの設定。
config/environments/developement.rbを編集する。
# Don't care if the mailer can't send #config.action_mailer.raise_delivery_errors = false config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :address => "localhost", :port => 25, :domain => "localhost", :authentication => :plain } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true config.action_mailer.default_charset = "utf-8"
元々の
config.action_mailer.raise_delivery_errors = false
は、エラーが起きてもシカトする設定なので、これをコメントアウトして、各行追記する。
4行目のところ、server_settingsではなく、smtp_settingsにしないと、mailerをgenerateするときに、
taka@taka-desktop:~/test$ ruby script/generate mailer OrderMailer confirm sent /usr/lib/ruby/gems/1.8/gems/actionmailer-2.1.0/lib/action_mailer/base.rb:385:in `method_missing': undefined method `server_settings=' for ActionMailer::Base:Class (NoMethodError) from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:455:in `send' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:455:in `initialize_framework_settings' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:454:in `each' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:454:in `initialize_framework_settings' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:451:in `each' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:451:in `initialize_framework_settings' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:133:in `process' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:93:in `send' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/initializer.rb:93:in `run' from /home/taka/test/config/environment.rb:13 from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /usr/lib/ruby/gems/1.8/gems/rails-2.1.0/lib/commands/generate.rb:1 from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require' from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from script/generate:3
のようなエラーが出てハマるので注意。
うまく実行されるとこんな感じ。
taka@taka-desktop:~/test$ ruby script/generate mailer OrderMailer confirm sent exists app/models/ create app/views/order_mailer exists test/unit/ create test/fixtures/order_mailer create app/models/order_mailer.rb create test/unit/order_mailer_test.rb create app/views/order_mailer/confirm.erb create test/fixtures/order_mailer/confirm create app/views/order_mailer/sent.erb create test/fixtures/order_mailer/sent
とりあえず送信できるかどうか試したいので、宛先とFromを設定する。
app/models/order_mailer.rb
def confirm(sent_at = Time.now) subject 'OrderMailer#confirm' recipients 'taka@localhost' from 'taka@localhost' sent_on sent_at body :greeting => 'Hi,' end
recipientsとfromをtaka@localhostに設定しました。
メールを送信するアクションをコントローラに定義する。
app/controllers/products_controller.rb
def send_mail OrderMailer.deliver_confirm redirect_to :action => :index end
メールを送信して、インデックスページにリダイレクトするだけのシンプルなアクションです。
ちなみに、create_confirmだと、作成したメールの内容が返されるだけで、メールは送信されません。(10分くらいハマった。。)
で、
http://localhost:3000/products/send_mail/1
にアクセス。
メーラ(Evolution)で確認したところ、
無事メールが送信されました。
ちなみに、日本語が化けるという情報もあるようですが、
私が確認した限りでは問題ありませんでした。