キーワードテーブルを追加して、キーワードで分類したい!

MySQLはリレーショナルデータベースと呼ばれている。リレーショナルデータベースでは、テーブル(単純な表)同士を関連付けして、複雑なことを扱えるようにするらしい。ちょうど表計算ソフトのlookup関数の使い方に似ているな...。それならリレーショナルデータベース風の使い方もしてみたいもんだ。
そこでまずは、登録したソフトウェアにキーワードを設定して分類しようと考えた。はてなブログ(このブログ)のカテゴリーみたいなものだ。だけど、とりあえず今は、一つのソフトウェアに複数のキーワードは設定できない仕様とする。
例えば、Ruby on Railsの環境を作るためのソフトウェアのキーワードは、みな「Ruby on Rails」にするのだ。キーワードには好きな単語を随時追加できるようにしたい。キーワードにはリンクを設定し、クリックするとそのキーワードに絞り込んだ一覧表示を行うようにしたい。

必要なこと(順不同)

  • データベースにキーワードテーブルを追加する。
  • キーワードテーブルを管理するモデル、コントローラも追加する。
  • キーワードテーブルを操作するコード。
  • ソフトウェアテーブルと、キーワードテーブルを関連付け。
  • ソフトウェアテーブルを操作する時にキーワードを表示するコード。
  • キーワードをクリックした時にそのキーワードに絞り込むコード。

マイグレーションを利用して、キーワードテーブルを追加

マイグレーションを利用するには script/generate model を実行しておいた方が無駄が無い。モデル作成時にマイグレーションファイルも自動生成してくれるから。よって、以下の手順で作業した。

  • まずはモデルの作成。Generatorsタブを選択して、modelを選択、その右項目にkeywordと入力して、Goボタン。
    • app/models/keyword.rbが作成される。
    • db/migrate/003_create_keywords.rbが作成される。
  • ついでなのでコントローラの作成。Generatorsタブのまま、controllerを選択、右項目はkeywordのまま、Goボタン。
    • app/controllers/keyword_controller.rbが作成される。
  • マイグレーションファイル 003_create_keywords.rb にテーブルの追加と削除をコーディング。追加したのは以下のように2行だけ。
class CreateKeywords < ActiveRecord::Migration
  def self.up
    create_table :keywords do |t|
      t.column :name, :string
    end
  end

  def self.down
    drop_table :keywords
  end
end
  • 上記を保存したら、マイグレーションの実行。Rake Tasksタブで、db:migrateを選択、Goボタン。
    • keywordテーブルが追加された履歴が、Consoleタブに表示される。

以上で、keywordのモデル、コントローラ、テーブルの追加は完了。

ソフトウェアテーブルとキーワードテーブルの関連付け

ソフトウェアテーブルにkeyword_idフィールドを追加

ソフトウェアテーブルには、関連するテーブル名_id、というフィールドが必要になる。

  • マイグレーションファイルの作成。Generatorsタブで、migrationを選択、その右項目にadd_column_keyword_idと入力、Goボタン。
    • db/migrate/004_add_column_keyword_id.rbが作成される。
  • マイグレーションファイル 004_add_column_keyword_id.rb を以下のようにコーディング。
class AddColumnKeywordId < ActiveRecord::Migration
  def self.up
    add_column :softwares, :keyword_id, :integer
  end

  def self.down
    remove_column :softwares, :keyword_id
  end
end
  • 上記を保存したら、マイグレーションの実行。Rake Tasksタブで、db:migrateを選択、Goボタン。
    • keyword_idが設定された履歴が、Consoleタブに表示される。
それぞれのモデルに関連付けをコーディング

コーディングと言っても、それぞれ1行ずつだ。1行コーディングはシンプルで分かりやすい!

モデル keyword.rb
app/models/keyword.rb
class Keyword < ActiveRecord::Base
  has_many :softwares
end

softwaresと複数形なので注意。
キーワードで分類するということは、キーワード中心に見ると、いくつものソフトウェアを保持すると考えるらしく、このように書く。

モデル software.rb
app/models/software.rb
class Software < ActiveRecord::Base
  validates_presence_of :title, :description, :url
  validates_format_of :url, :with => URI.regexp(['http', 'https', 'ftp'])
  belongs_to :keyword
end

こちらはkeywordと単数系。
今度はソフトウェア中心に見ると、キーワードに属すると考えるらしいので、このように書く。

キーワードテーブルを操作するコード、もう一つのscaffold

キーワードテーブルへデータを追加、削除、表示するコードが必要だ。これまでのようにscript/generate scaffoldで、コードを自動生成する方法が思い浮かぶが、scaffoldにはもう一つの使い方がある。今回は、その方法でやってみる。

コントローラ keyword_controller.rb
app/controllers/keyword_controller.rb
class KeywordController < ApplicationController
  scaffold :keyword
end

何と、ここでもコントローラに1行書くだけ。

まだ、ソフトウェアの操作画面から、キーワードの操作画面にはリンクしてないので、URLを直接入力して操作を試してみる。

http://0.0.0.0:3000/keywords

すると、こんなエラーが出てしまった。

どこかで間違ったのかと思い、コードを見直したが(といっても1行だけなので間違いようが無い)問題なく、しばし悩んでしまった。
問題は、URLアドレスだった。「s」が余分だったのだ。これでアクセスできた。

http://0.0.0.0:3000/keyword

適当なキーワードを登録しておく。

      • script/generate scaffoldでコードを自動作成した場合は、http://0.0.0.0:3000/softwaresと複数形でアクセスできたのだが、メソッド呼び出しでscaffoldを使った場合は、単数系でアクセスすることになるようだ。
      • いや、これは正確な認識ではなかった...。script/generate model keywordでモデルを作った後、すぐにscript/generate controller keywordでコントローラを作ったが、ここでコントローラ名の指定をkeywordsと複数形で指定すれば、URLも複数形でアクセスできるようになった。コントローラは複数形で指定するのが正しいのかもしれない...。
      • それにしても、script/generate modelも、script/generate scaffoldも単数系で指定するのに、script/generate controllerだけ複数形にしなくちゃいけないのは何か理由があるのだろうか?複数形が必須条件なら、scaffoldのように自動的に複数形に変換してくれればいいに...。
      • 複数形なのか、単数系なのか、英語の苦手な人にとっては理解し難い感覚だ。

ちょっと悩んでしまったが、どうにかここまで終了。


残る課題は二つだけになった。

  • ソフトウェアテーブルを操作する時にキーワードを表示するコード。
  • キーワードをクリックした時にそのキーワードに絞り込むコード。