Ruby on Rails – 開発中のテーブル調整

「最初にガチガチに設計してから開発する」というスタイルをとらない場合(個人開発・趣味開発の場合はほとんどがあてはまると思います)、開発が進行するに伴って、モデル(データベーステーブルの設計)を変更していきたいと思うはずです。

このようなとき、先の記事にも書きましたが、db/migrateにあるファイルを変更するだけでは、データベースに反映が行われない場合があります。正しくは、マイグレーション機能を使ってインクリメンタルに変更していかなければなりません。しかし、個人で開発する場合、これは面倒です。テーブル数が少ない、カラム数が少ない、といった小規模開発の場合は、とくに当てはまります。

そんなわけで、たぶん正しいやり方ではありませんが、db/migrateのファイルを直接編集する場合の力技的な方法をメモしておきます。

1
2
3
$ rm db/migrate/*.sqlite3 db/schema.rb
$ rake db:create
$ rake db:migrate

要は、データベースファイルとスキーマファイルを削除して、データベース関連ファイルを再構築するだけです。すでに完成したバージョンの上で動かしたい場合は、その時点のデータベースファイルとスキーマファイルを保存しておいて、巻き戻したいときはそれらのファイルで上書きコピーしてしまえばいいということになります。このとき、編集するdb/migrateのファイルを間違えないように注意(そんなことはしないと思いますが…)。

Ruby on Rails – データベースのマイグレーション

Ruby on Railsで開発中、「このテーブルのカラム名を変更したい」「このテーブルの構造を変更したい」といった事態が生じると思います。

こんなとき、最初はdb/migrateの下にできたファイルを編集すればいいのだと思っていました。しかし、いくら変更しても、追加したカラムが反映されない。どうもおかしい。なぜだろう、といろいろ見てみると、db/schema.rbというファイルでデータベースの構造を管理していることが分かりました。こちらも編集すると、追加したカラムなどが反映されます。

しかし、このような方法は推奨されない、というかやってはならないものみたいです。rails generate modelした直後に変更するなどならまだしも、以前に作られたものを変更するなどすると、もはや元に戻せなくなり、困ったことになりかねません。ちょっとした変更でも、ちゃんとジェネレータを介して操作した方がいいようですね。

Ruby on Rails – コントローラのメソッド

Ruby on Railsは、さまざまな「慣習」を用いて、コーディングしなければならない分量を減らす作戦を用いています。

コントローラのメソッド名も、そのなかの一つ。こういう「暗黙のルール」をまとめておいてくれる場所って、ないものですかねえ。まあ、ドキュメントの全部を把握していない段階では、すべてが「暗黙のルール」に見えるわけですけれども。いや、ドキュメントに書かれていれば「明示のルール」なのかな?

それはさておき。

RailsGuidesのRails Routing from the Outside Inによれば、HTTPリクエストの命令とパスによって、コントローラのうち呼び出されるメソッドが決定されるとのことです。ドキュメントの位置からも分かるとおり、これは「ルーティング」に分類されるルールです。リクエストに応じて適切なコントローラのメソッドを呼び出すのですから、確かにルーティングですね。

ただし、これは自動的に設定されるわけではなく、routes.rbで明示的に指定する必要があります。

1
resources :controller1, :controller2, ...

なお、resourceではなく、resources(複数形)なので注意してください。単数形の方は、パスの中にIDを含まない(パラメータでIDを指定する)ものになります。複数形の方は、パスの中にIDを指定するものになります。

resourcesで使用されるメソッド名は、次の7つです。

メソッド名 対応するHTTPリクエスト
index GET / パス=/example
new GET / パス=/example/new
create POST / パス=/example
show GET / パス=/example/[ID]
edit GET / パス=/example/[ID]/edit
update PUT / パス=/example/[ID]
destroy DELETE / パス=/example/[ID]

コントローラでこれらのメソッドすべてを実装する必要はありませんが、特定のHTTPリクエストが送られてきたとき、対応するメソッドが定義されていないとエラー(ページ)が返されます。

Ruby on Rails – 先人の軌跡

探せばあるもので、Ruby on Railsの基本的な部分については、「Ruby on Rails 3.0 日記」で解説がなされていました。Railsを以前から使っている方が書いた記事のようで、ちゃんと「分かっている」方が書いた内容となっています。また、スクリーンショットも多用されているので、分かりやすいないようになっています。

すでにいろいろと書きましたが、ぜんぶ忘れてください(笑)。上記記事を参照すれば、Ruby on Railsの基本的なところは分かると思います。

ここでは、作業記録的なものを書いていこうと思います。

Ruby on Rails – 設計

Ruby on Railsが動作するようになったところで、アプリケーションの完成形をイメージしていきます。抽象的な事項(アプリケーションが提供する機能)は先に掲げたとおりですので、その機能を提供するための具体的な方法や手順について考えていきます。これにより、アプリケーションがどのようなウェブページを提供しなければならないのか、そして何を作らなければならないのか、明らかになっていきます。

Anacondaは、情報源を外部に頼ります。そのため、「どのような情報が存在するのか」をシステムに知らせてあげなければなりません。情報はIDによって識別するものとします。Evernoteは各ノートにGUIDを割り当てているので、このGUIDをIDとして使えばいいでしょう。Spiderで考えれば、ネットワークのGUIDと、情報オブジェクトの番号を組み合わせた文字列がIDになります。Anacondaは、まず最初に、このID収集を行う必要があります。IDを収集する際、同時に、どの情報源から取得したのかも記録しておく必要がありますね。

使用する情報のIDが集め終わったら、反復学習を始めることができます。以前にチェックした日時と、そのときのユーザー評価から、表示すべき状態にある情報を選び出し、表示します。そして、ユーザーは表示された情報についてチェックし、もう表示する必要はない、ある程度分かったので次のチェックは先でよい、分かっていなかったので次のチェックは近くに行う、などの評価を与えます。メモを残せるようにしてもよいですが、現時点では見送ることにしましょう。ある情報についてチェックが終わったら、次の情報を表示します。表示すべき状態にある情報が無ければ、その日の分は終了したということになります。

なかなか理解が進まない情報や、全体に対する進捗情報などを確認する、分析的な処理もあると便利ですね。しかし、これも現時点では見送ることにしましょう。いつか追加する予定がある、という程度に捉えておきます。

以上から、Anacondaが提供すべきウェブページは、次のようになります。

  • ID収集・学習などの機能へ分岐するトップページ。
  • ID収集のため、収集元を選択するページ。
  • 表示すべき状態にある情報を表示し、それに対する評価を与えるためのページ。

とりあえずは、トップページから作っていくことにしましょう。

とは言ったものの、何を編集すればよいのか分かりません。Ruby on Railsのガイドを見ながら進めていくことにします。

まずはアプリケーションを作成します。

1
$ rails new Anaconda

詳しい仕組みはまだ分からないのですが、サイト上のルートディレクトリはプロジェクト上のpublic/に相当し、ここにindex.htmlというファイルが存在すれば、これを読み込むようです。静的なウェブページを使うことはないはずなので、削除してしまいます。すると、ルーティングに失敗するというエラーが出るようになります。ルートディレクトリについて表示すべきファイルがないため、エラーが出ているようです。そこで、表示すべきページを作成することにします。これは、Ruby on Railsが提供する機能を使って自動的に行うことができます。

1
$ rails generate controller index home

次に、ルーティングを行うファイルに、ルートディレクトリとして表示すべきものの位置を教えてあげる必要があります。config/routes.rbを開き、次の行を書き加えます。

1
  root :to => "home#index"

ルートとして、"home#index"を指定するという意味です。これは、コントローラhomeindexメソッドを表しており、homeというページのindexというラベルを表すものではありません。ここまで書き加えれば、サーバを起動して、http://localhost:3000にアクセスすることで、homeコントローラのindexメソッドが呼び出されていることを確認できます(表示されているのはビューhomeindex.html.erb)。

ところで、config/routes.rbには、次の行も追加されています(railsコマンドで自動的に追加される)。

1
  get "home/index"

これは、パスhome/indexに対するHTTPのGETリクエストを許可するという意味です。呼び出されるのは、homeコントローラのindexメソッドになります。この行を取り除く前はhttp://localhost:3000/home/indexに対するアクセスが成功し、取り除いた後はhttp://localhost:3000/home/indexに対するアクセスがエラーを返すようになります。home/indexは使わないので、取り除いておきます。

サーバの起動は、次のようにして行います。

1
$ rails server

いきなり「コントローラ」や「ビュー」という言葉が出てきました。これは、MVCモデルのControllerとViewのことです。Ruby on RailsはMVCモデルを採用しています。これによって、論理のコードと表示のコードを分離することができ、開発を局所に集中して行うことができるようになります。なお、Rubyはとても緩い言語ですので、表示に関する処理のみをすべきであるビューに、データ操作に関する処理を入れてしまうことができます(たぶん)。これをやるとMVCモデルを採用している意味が完全に失われてしまうので、自分がいまどの部分について作業しているのか、しっかりと自覚しておく必要があります。まだModelが出てきていませんけれども、じきに登場します。

Ruby on Rails – 下準備

Ruby on Railsはスクリプト言語Rubyで動作するので、まずはRubyをインストールするところから始めます。なお、環境はWindowsです。

Rubyの公式サイトからダウンロードしてもよいのですが、RubyInstallerというパッケージを使うのも楽です。これは、Windows用にRubyをビルドした環境をパッケージにしたものです。実行形式のインストーラーもあるので、楽ではあります。単にアーカイブしただけのパッケージもあるので、変なインストーラーは使いたくないという方は、そちらも使えます。使うRubyのバージョンは、もちろん最新版(執筆時点で1.9.2)。いまさら1.8系を使うのも、時代遅れというものです。幸いなことに、Ruby on Railsも3.0以降はRuby 1.9をベースにしているようです。

次に、Ruby on Railsをインストールします。

Rubyを使える状態にして(環境変数PATHにRubyの実行ファイルが格納されたディレクトリを追加する)、Rubyのパッケージマネージャgemを使えるようにしておきます(いまは標準添付されている?)。ここまでできたら、gem install railsするだけです。

1
$ gem install rails

自分の環境では、マニュアルをコンパイルしているところでエラーが発生しました。しかし、全体としては問題なく動作しているので、無視しています。何も指定しなければ、安定した最新版がインストールされることになるでしょう(執筆時点で3.0.9)。

次に、SQLite3をインストールします。これは必須ではないのですが、開発段階からMySQLなどフルセットのデータベースを使うのは設定が面倒ですから、それらの面倒を省くことのできるSQLiteを導入しておいた方が楽だと思います。

まず、gemで必要なRubyライブラリをインストールします。

1
$ gem install sqlite3

次に、SQLiteのホームページからsqlite3.dllをダウンロードします。ダウンロードしたら、適当なディレクトリにDLLを展開し、環境変数PATHを通します。ここまで終わったら、正常に動作するか、チェックしておきましょう。

1
$ ruby -e 'require "sqlite3"'

さて、ここで、rake 0.9以降を使っている場合(?)、rakeがうまく動作しないという問題があります。理由はよく分からないのですが、こちらで紹介されている解決方法を実行すると、確かにエラーが出なくなりました。どうやら、rakeのバージョンによって挙動が違っているようで、それが悪さをしているようです。この対処により正しく動作しているような感じですが、まだちょっと分かりません(のちに検証して追記するなどします)。

まだ方法は紹介していませんが、作成したプロジェクトにあるGemfileに次の行を書き加えます。

1
gem 'rake', '0.8.7'

そして、次のコマンドを実行します。

1
2
$ bundle unlock
$ bundle update

こちらの情報によれば、Gemfile修正後、次のコマンドを実行するのでもいいようです。

1
$ bundle update rake

ちなみに、bundleとはBundlerというプロジェクトが提供するプログラムで、アプリケーション相互の依存関係を管理するために作られたものだそうです。

Ruby on Railsは素晴らしいフレームワークですが(そうなのだそうだ)、さまざまな技術を利用しているので、「果たしてこの機能は何が提供しているんだろうか?」と疑問に思ってしまうことがしばしばです。なにやら、Active Supportという、Rubyの標準ライブラリに(ウェブアプリ開発に)便利な機能を多数追加するという芸当をやっているそうで、これも「果たしてこの機能はRubyが標準で提供しているものなのだろうか?」と思ってしまうことが多いそうです。おいおい分かってくると思いますが、「どこまでがRailsなのか」をしっかり把握しておくようにしたいと思います。まあ、そのうち、そんなことを考えなくてもいい時代が到来するのかもしれませんが。

Project Anaconda

Evernoteの発見により、Spiderは瀕死の重傷を負ってしまいました。

細かい点を見れば存在価値も見出せるので、息の根を止められたというわけではないのですが、はたしてそれらのために作り続けるだけの価値があるのかというと難しいところがあるので、再起不能の重傷を負ってしまったといえるでしょう。

一方、Spiderを利用して作ろうとしていたアプリケーションは、Evernote単体では実現できない機能を提供するので、少なからぬ動揺を受けてはいるものの、未だ健在です。

何を作ろうとしていたかといえば、反復学習のためのアプリケーションです。学習は、新たに取得した記憶を自身に定着することで進んでいく側面があります。これは、同じことを繰り返し行うことで実現されるのですが、自分で意識的に行おうとするとなかなか難しいところがあります。効果的な反復学習を行うには、一定の時間を空けることが必要といわれています。どの情報を、いつ取り組んだのか、すべて自分で管理するのは、情報が増えれば増えるほど難しいものです。そのため、アプリケーションによる学習履歴の管理が必要となるのであり、類似のソフトウェアも存在するようですが、わたしが望む機能を備えているものは無いようです。

このようなソフトウェアを、まるで知識に巻き付いて取り込んでいくものだということで、Anacondaと名付けました。

最初はSpiderのネットワークを利用してアプリケーションを構築しようと考えていたのですが、先述のとおり、Spiderは再起不能となってしまったので、依って立つ土台を大きく変える必要があります。

どうやら、Evernoteは、付属するアプリケーションや、Web APIを利用することで、そのデータベースにアクセスすることができるとのことです。だとすれば、ウェブアプリケーションとの親和性が強いということになります。ウェブアプリといえば真っ先に思い浮かぶのはPHPですが、個人的には、あまり好きではありません。使えるものならば、Rubyを使いたい。そういえば、Rubyにも優秀なフレームワークとしてRuby on Railsというものがあります。噂には聞くのですが、実際に使ったことはありません。

ということで、Ruby on Railsを使って、Anacondaを実装することに決定しました。

とはいえ、Ruby on Railsに関しては素人なので、「流儀」を学びながらの開発となります。その過程については、このブログに書き込んでいく予定です。

さて。まずはAnacondaが備えるべき機能を明らかにしておきましょう。いわば、これから歩む道の到達点です。

  • ある情報について、チェックした日時の履歴を管理することができる。
  • チェックした日時の情報をもとに、現在においてチェックすべき情報を選び出すことができる。
  • もととなる情報は、独自形式を用いず、(ある程度)一般的な形式による。すなわち、他のアプリケーションでも利用できるものとする。

ひとまずは、こんなところです。すでに作成に取りかかっていることもあるので、これは枝葉を取り除いた後の姿になっています。最初はいろいろと別の機能も搭載することを考えていたのですが、そうすると「これは一体いつ完成するのか?」ということになってしまうので、できるだけシンプルな機能だけを搭載することにしました。その代わり、外部とのインターフェイスには最大限の柔軟性を持たせ、多様な外部アプリケーションとの連携を前提としています。

JUnit4のテストとコンストラクタ

Spiderの開発では、JUnit4による自動テストを行っています。オブジェクトの検索処理が心臓部となるので、その正確性を確認しておかなければなりませんし、性質上テストしやすいものでもあるからです。

JUnit4は、アノテーションを使ってテストメソッドなどを指定します。具体的には、@Testを付したメソッドはテストされ、@Before@Afterを付したメソッドはテストメソッドの実行前後に呼び出されます。

ここで、見落としがちなのは、テストメソッドを有するテストクラスのコンストラクタがいつ呼び出されるのか、という点です。

わたしの認識では、何度もテストクラスのオブジェクトを構築するのは無駄ですから、テストクラスのオブジェクトが構築されると、以後、そのオブジェクトが使い回されるものと思っていました。しかし、実際には、テストメソッドを実行するたびに新たなテストクラスのオブジェクトが構築されます。これを見落とすと、初期化されているはずのフィールドが初期化されていなかったり、値を設定したはずのフィールドに何も設定されていないという事態が生じることになります。

なお、JUnit4のAPIリファレンスには、「To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method.」と書かれており、アノテーションが付されたメソッドを呼び出すときには、JUnitは新しいインスタンスを生成するということが明記されています。その他に、このことについて言及しているドキュメントはあったのでしょうか。自分としては、見かけませんでした。

EclipseでSubversion(リポジトリー作成編)

Subversiveのチーム・プロバイダーとコネクターをインストールすると、Subversionを使ったバージョン管理をEclipse上で行うことができるようになります。

すでにSubversionを使ったプロジェクトを進めている場合は、「ファイル」→「インポート」から「SVN」→「SVNからプロジェクト」を選ぶことで、ソースコードなどをローカルにダウンロードできます。

これから新しくプロジェクトを作る場合は、「ウィンドウ」→「ビューの表示」→「その他」から「SVN」→「SVN リポジトリー・ブラウザー」を選びます。すると、同名のビューが開かれるので、リスト上で右クリックをしてメニューを表示し、「新規」→「リポジトリー」を選びます。小さなダイアログが表示されるので、テキストボックスにリポジトリーを作成する場所を入力します(「参照」でディレクトリツリーから選べます)。ここで指定した場所に、Subversionのリポジトリが作成されます。なお、リポジトリーとは、ソースコードなどプロジェクトの情報を蓄積する場所で、Subversionを使ううえで必須のものです。

リポジトリーの用意ができたら、パッケージ・エクスプローラーなどで、バージョン管理したいプロジェクトを選んで右クリックし、「チーム」→「プロジェクトの共用」を選びます。方式を選ぶダイアログが表示されるので、「SVN」を選んで進めます。使用するリポジトリーには、先ほど作成した、ローカルのリポジトリーを指定します。

EclipseでSubversion(インストール編)

唐突ですが、EclipseでSubversionを使うための方法について書いていきたいと思います。

なぜSubversionか。

なんででしょうね。

すみません、よく知らないんです。なにやら、このごろ流行っているらしいということくらいしか。このごろ? だいぶ前からありますね。CVSよりも優れたバージョン管理システムという話を聞いており、最近はSubversionが使われることも多いらしいということで、使ってみようと思いました。

EclipseでSubversionを使うためには、いくつかのプラグインを導入する必要があります。プラグインそのものにもいくつかの種類があるようですけれども、EclipseプロジェクトのひとつになっているSubversiveを導入することにします。なお、使うEclipseは3.6(コードネームHelios)です。また、MergeDocにより日本語化がなされていることを前提とします。

ホームページのDownloadsにはHelios用のリリース版が用意されているので、これを使います。zipをダウンロードするのもよいですが、アップデートサイトを利用した方が簡単でしょう。プラグインを配布しているサイトはEclipseに組み込まれているので、特別な追加処理は必要ありません。「ヘルプ」→「新規ソフトウェアのインストール」でインストールというダイアログを開き、「作業対象」の横にあるコンボボックスで「Helios – http://download.eclipse.org/releases/helios」を選びます。すると、下のリストにプラグインのカテゴリが表示されるので、「コラボレーション」を開き、「Subversion SVN チーム・プロバイダー(インキュベーション)」の横をチェックします。あとは、そのまま決定をしてインストールしていけば完了です。

次に、SVNコネクタが必要となります。Subversiveのドキュメントによると、チーム・プロバイダーのプラグインをインストールしてEclipseを再起動するとSubversiveコネクタを導入するためのダイアログが表示されるとのことです。しかし、わたしの環境では表示されなかったので、自前でインストールすることにしました。

Polarionというサイトに書かれているとおり、「http://community.polarion.com/projects/subversive/download/eclipse/2.0/helios-site/」を更新サイトのリポジトリーに追加して(「ヘルプ」→「新規ソフトウェアのインストール」→「追加」)(リポジトリーの名前は適当、たとえばSubversive SVN Connectors)、「Subversion SVNコネクター」の下にある「Subversion SVNコネクター」と「SVNKit 1.3.5 実装」にチェックをして、インストールします。ほかにJavaHLというものもありますが、実装方法の違いにすぎないので、SVNKitと好きな方を選んで構いません。ちなみに、SVNKitはPure JavaなSubversionの実装です。

チーム・プロバイダーとコネクターをインストールすれば、EclipseでSVNが使えるようになります。具体的な使い方については、次回ということで。