はじめに
妻がやってるパン屋さんのWebサイトを変更してみました。
変更と言っても、トップページにRSS経由で最新のブログ記事へのリンクを表示する、ただそれだけの変更です。
妻は週に1〜2回ブログを更新しますが、店のサイトの方は最近放置状態なので、ちょっとでもサイトに変化を与えようと思い、この改造に着手しました。
特別珍しいことをやるわけでもないし、こんなん楽勝、楽勝!!・・・と思ってたら、予想以上に時間がかかってしまいました。(T T)
トータル5〜6時間ぐらい??
終わってみたら「なんだこれだけかいっ!」って思うんですが、その解決策に至るまでの道のりは非常に険しかったです。ま、簡単にいうと「ハマってた」ということなんですが。
もしかするとどこかの誰かの役に立つかもしれないので、技術メモを残しておきます。
Rails3.0から3.1への移行
最初にGoogleで見かけたサンプルはjQueryを使ってRSSフィードを取得していました。
Rails3.0はprototype.jsで、3.1からjQueryがデフォルトになったようなので、この際3.1に移行しようと思いました。(この選択で後で大きく困らされたのですが・・・)
Gemfile
まずはGemfileを変更します。
# Gemfile -gem 'rails', '3.0.9' +gem 'rails', '3.1.3'
「bundle install(updateだったかも)」で、移行終了〜!!・・・というわけにはいきません。
sqliteのバージョンを1.3.3に固定していたのですが、ダメみたいなのでバージョンを「1.3.0以上」に変更します。
# Gemfile -gem 'sqlite3', '1.3.3' +gem 'sqlite3', '~> 1.3.0'
debug_rjs
Ajax周りの仕様が変更されたため、config/environments/development.rbに以下の一行があるとエラーになります。というわけで削除!
# config/environments/development.rb -config.action_view.debug_rjs = true
Tableless Model
Webサイトには問い合わせフォームがあります。
単純なフォームなのでRailsの便利なバリデータを使いたいのですが、送信情報自体はデータベースに格納しません。
なので、データベーステーブルに依存しないモデルを作成しました。
Rails3.0では以下のようなコードで動いていたのですが、3.1になると「ActiveRecord::ConnectionNotEstablished」というエラーが出ました。
# http://railscasts.com/episodes/193-tableless-model:title class Inquiry < ActiveRecord::Base def self.columns() @columns ||= []; end def self.column(name, sql_type = nil, default = nil, null = true) columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null) end column :name, :string column :email, :string column :tel, :string column :text, :text end
これはあれこれ探しまくって、結局以下のような形に落ち着きました。
# http://stackoverflow.com/questions/7275496/tableless-model-in-rails-3-1 class Inquiry include ActiveModel::Validations include ActiveModel::Conversion extend ActiveModel::Naming attr_accessor :name, :email, :tel, :text validates :name, :email, :text, presence: true def initialize(attributes = {}) if attributes attributes.each do |name, value| send("#{name}=", value) end end end def persisted? false end end
RawOutputHelper => OutputSafetyHelper
問い合わせフォームで入力値エラーがあった際にdivタグではなくspanタグでエラーメッセージを出力したかったので、config/application.rbに以下のようなおまじないを埋め込んでいたのですが、「rawメソッドが見つからない」と怒られてこれも動かなくなりました。
# config/application.rb # http://www.rabbitcreative.com/2010/09/20/rails-3-still-fucking-up-field_with_errors/ ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| include ActionView::Helpers::RawOutputHelper raw %(<span class="field_with_errors">#{html_tag}</span>) end
どうやらRawOutputHelperというクラスがなくなったようなので、「ActionView::Helpers::OutputSafetyHelper」という新しいクラスに変更しています。
# config/application.rb -include ActionView::Helpers::RawOutputHelper +include ActionView::Helpers::OutputSafetyHelper
ここまでやってようやくローカルでRails3.1が動作するようになりました。
RSS(Atom)の取得
最初はjQueryでやろうと思っていたのですが、ネットのサンプルコードがうまく動かなかったので結局サーバーサイドで実装することにしました。
ということで無理に3.1にしなくても良かった!ということになるんですが・・・。(T T)
それはさておき、あれこれ説明するより、コードを見た方が速いです。
こんなヘルパーメソッドを作って、Viewで呼び出すようにしました。
require 'feed-normalizer' module PagesHelper def load_blog source = "http://rss.exblog.jp/rss/exblog/lapin418/atom.xml" feed = FeedNormalizer::FeedNormalizer.parse(open(source), :force_parser => FeedNormalizer::SimpleRssParser).items[0] @blog_title = feed.title.force_encoding('utf-8') @blog_date = feed.date_published.strftime(" (%Y/%m/%d)") @blog_url = feed.urls[0] end end
そうそう、feed-normalizerも忘れずにインストールしておきましょう。
# Gemfile +gem 'feed-normalizer'
ところで、最初はこのサイト(RubyRSS)に載ってる方法を試していたんですが、parseしてもnilが返ってきてしまい、動きませんでした。
どうやらRSSとAtomは別物のようで、Atom用のコードを書く必要があるようです。(jQueryのサンプルコードが動かなかったのもたぶんそのせい?)
また、ブログのタイトルを表示しようとすると「incompatible character encodings: UTF-8 and ASCII-8BIT」というエラーが出たため、「feed.title.force_encoding('utf-8')」のようにエンコードを指定する必要がありました。
Herokuへのデプロイ
さあ、ようやくローカルでちゃんと動いた!あとはデプロイしたらおしまい〜!!・・・と思ったら、まだ罠がありました。
Herokuにデプロイするとエラーが発生します。
ログを見ると、またまた「ActiveRecord::ConnectionNotEstablished」とありました。
ググってみると、config/application.rbで読み込むモジュールを個別に指定する必要があるとのことでした。
# config/application.rb -require 'rails/all' +# http://www.benjaminoakes.com/2011/09/15/activerecordconnectionnotestablished-in-rails-3-1-on-heroku/ +require "action_controller/railtie" +require "action_mailer/railtie" +require "active_resource/railtie" +require "sprockets/railtie" +require "rails/test_unit/railtie" +require "active_record"
タイムゾーンの設定
今度こそOK〜!!・・・と思ったら、今度はブログの更新日がなんか違う。
タイムゾーンがズレているようです。
こちらの記事を参考にして、Herokuのタイムゾーンを設定しました。
heroku config:add TZ=Asia/Tokyo
タイムゾーンを変更しないやり方もあるみたいですが、僕は安易に手っ取り早い解決策を選択しました。^^;
やっと完成!!
ここまでやって、ようやくRails3.1への移行 + 最新ブログ表示機能の完成です!
実際のページはこちらになります。↓
たったコレだけのために5〜6時間とは・・・悲しいです。
まあRailsに限らず、初めて挑戦することは簡単そうに見えても結構泣かされますもんね。
仕方がない、きっと!!と、自分で自分を励ましておきます。
すでにRailsは3.2が出ていますが、僕と同じように3.0から3.1に移行しようと思っている人は参考にしてみてください。
あわせて読みたい
夫から見たパン屋さんの舞台裏 - give IT a try
僕から見たお店の様子を紹介しています。
「Coupe Baguette」のWebサイトができあがるまで - give IT a try
最初にWebサイトを作った時の技術情報を載せています。
A programmer in Japan: Raw method was moved to OutputSafetyHelper in Rails 3.1 or later
RawOutputHelper から OutputSafetyHelper への変更はググっても明確な情報源がなかったので英語ブログに載せてみました。