テーブル間での連携

テーブルとテーブルを結合してみる。

道具には作った人がいるだろうということで、creatorテーブルを追加。
まずは、新しいテーブルをscaffoldでcreateする。

>ruby script/generate scaffold creator name:string

「db/migrate/003_create_creators.rb」が出来上がってるので、

>rake db:migrate

でテーブルを生成。

http://localhost:3000/creators」からデータをちょこちょこ追加してあげると、

Name
smith      Show  Edit  Destroy
herbalist  Show  Edit  Destroy

こんな感じに。
smithは鍛治屋、herbalistは薬草師のこと。

でもって、このcreatorテーブルと、itemテーブルを繋ぐために、
itemテーブルに、creator_idフィールドを追加する。

migrationファイルをgenerateすると、

>ruby script/generate migration AddItemsCreatorID

「db/migrate/004_add_items_creator_id.rb」ができあがるので、

class AddItemsCreatorId < ActiveRecord::Migration
  def self.up
    add_column :items, :creator_id, :integer
  end

  def self.down
    remove_column :items, :creator_id, :integer
  end
end

こんな感じで、itemテーブルにcreator_idフィールドを追加する記述をする。

最後に、

>rake db:migrate

で、DB生成完了。

>sqlite3 db/development.sqlite3

で中身を見てみると、

sqlite> .table
creators     items        schema_info

ちゃんとcreatorsテーブルが生成されていて、

sqlite> .schema
CREATE TABLE creators (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
"name" varchar(255) DEFAULT NULL, 
"created_at" datetime DEFAULT NULL, 
"updated_at" datetime DEFAULT NULL
);
CREATE TABLE items (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
"name" varchar(255) DEFAULT NULL, 
"price" integer DEFAULT NULL, 
"created_at" datetime DEFAULT NULL, 
"updated_at" datetime DEFAULT NULL, 
"number_of_times" integer, 
"creator_id" integer
);
CREATE TABLE schema_info (version integer);

itemsテーブルには、creator_idも追加されてるのが確認できる。

でもって、テーブルを結合するのに、
「/app/models/creator.rb」に

class Creator < ActiveRecord::Base
  has_many :items
end

「/app/models/item.rb」に

class Item < ActiveRecord::Base
  belongs_to :creator
end

を追記する。
creatorは、itemを複数持つので複数形、itemは、creatorが1つ(1人)だけなので単数形なのに注意。

あとはitemsビューのerbファイルに、creatorのidとnameを表示と修正できるようにちょこちょこっとコード追加。
ひとまずcreator_idはidを手入力でよしとする。
(鍛治屋は1、薬草師は2)

でもって、indexは、

    <td><%=h item.name %></td>
    <td><%=h item.price %></td>
    <td><%=h item.number_of_times %></td>
    <td><%=h item.creator_id %></td>
    <td><%=h item.creator.name %></td>
    <td><%= link_to 'Show', item %></td>
    <td><%= link_to 'Edit', edit_item_path(item) %></td>
    <td><%= link_to 'Destroy', item, :confirm => 'Are you sure?', :method => :delete %></td>

てな具合で、idとnameを表示するようにする。

あとは、「http://localhost:3000/items」を見ると、

Name       Price    Number of times      Creator id      Creator name
ポーション 100      1                    2               herbalist     Show     Edit     Destroy
毒消し     80       1                    2               herbalist     Show     Edit     Destroy
ナイフ     1000     100                  1               smith         Show     Edit     Destroy
ソード     2000     500                  1               smith         Show     Edit     Destroy

となる。

テーブルを関連付けると、itemsテーブルから"."繋ぎでcreatorsテーブル
を参照できるようになる。

fieldを追加してみる

アイテムデータが出来上がったが、道具というものは使用回数があるわけです。

ということで、各アイテムに使用回数のデータも持たせてみる。

fieldの追加は、

>ruby script/generate migration AddNumberOfTimes

で、migrationファイルをgenerate。
新しく「db/migrate/002_add_number_of_times.rb」なるものが生成されるので、

class AddNumberOfTimes < ActiveRecord::Migration
  def self.up
    add_column :items, :number_of_times, :integer
  end

  def self.down
    remove_column :items, :number_of_times, :integer
  end
end

中身をこんな具合に修正してから、

>rake db:migrate

で、データベースを再生成。

http://localhost:3000/items」を覗くと、変化なし。
っと、ビューを修正しないと当然だわな。

ということで「app/veiws/items」以下のerbファイルを使用回数に対応するように追記。

Editアクションでちょこちょことアイテムデータを修正すると、

Name        Price  Number of times 
ポーション  100    1                Show Edit Destroy
毒消し      80     1                Show Edit Destroy
ナイフ      1000   100              Show Edit Destroy
ソード      2000   500              Show Edit Destroy

てな具合に、アイテムの使用回数のフィールドが追加されてるのが確認できる。

railsコマンドを使ってみる

helpも読んだので、早速使ってみる。

>rails test1

ディレクトリ作成開始。
特に必要を感じないのでオプションは無し。

--quietオプションで表示を抑制してないので、作成ディレクトリ・ファイルがずらずらと表示される。

 create  app/controllers
 create  app/helpers
 create  app/models
 create  app/views/layouts
 create  config/environments
 create  config/initializers
 create  db
 create  doc
 create  lib
 create  lib/tasks
 create  log
 create  public/images
 create  public/javascripts
 create  public/stylesheets
 create  script/performance
 create  script/process
 create  test/fixtures
 create  test/functional
 create  test/integration
 create  test/mocks/development
 create  test/mocks/test
 create  test/unit
 create  vendor
 create  vendor/plugins
 create  tmp/sessions
 create  tmp/sockets
 create  tmp/cache
 create  tmp/pids
 create  Rakefile
 create  README
 create  app/controllers/application.rb
 create  app/helpers/application_helper.rb
 create  test/test_helper.rb
 create  config/database.yml
 create  config/routes.rb
 create  public/.htaccess
 create  config/initializers/inflections.rb
 create  config/initializers/mime_types.rb
 create  config/boot.rb
 create  config/environment.rb
 create  config/environments/production.rb
 create  config/environments/development.rb
 create  config/environments/test.rb
 create  script/about
 create  script/console
 create  script/destroy
 create  script/generate
 create  script/performance/benchmarker
 create  script/performance/profiler
 create  script/performance/request
 create  script/process/reaper
 create  script/process/spawner
 create  script/process/inspector
 create  script/runner
 create  script/server
 create  script/plugin
 create  public/dispatch.rb
 create  public/dispatch.cgi
 create  public/dispatch.fcgi
 create  public/404.html
 create  public/422.html
 create  public/500.html
 create  public/index.html
 create  public/favicon.ico
 create  public/robots.txt
 create  public/images/rails.png
 create  public/javascripts/prototype.js
 create  public/javascripts/effects.js
 create  public/javascripts/dragdrop.js
 create  public/javascripts/controls.js
 create  public/javascripts/application.js
 create  doc/README_FOR_APP
 create  log/server.log
 create  log/production.log
 create  log/development.log
 create  log/test.log

1割程度しか、なんのためのディレクトリ・ファイルかわからないけども、気にしない。
そのうち把握できるでしょう、たぶん。

railsコマンドのhelpを見てみる

使い方は、

>rails アプリのディレクトリ名 [options]

まあ、これだけ知ってれば問題ないんだけども、helpは一度読んでおいたほうがいいよなぁってことでhelpも見てみる。

以下、optionsの意味。

-r, --ruby=path

Rubyのインストールpath指定。
デフォルトpathは、c:/ruby/bin/ruby
Railsを使うなら素直にCドライブ直下にRubyをインストールしとくのが無難ぽい。
実装の都合でRubyのverを固定したいときとかにうれしいオプションかな?

-d, --database=name

使用するデータベース指定。
選択肢として、MySQL/Oracle/PostgreSQL/SQLite2/SQLite3。
helpではデフォルトがMySQLとなっているが、Rails2.0.2以降はSQLite3がデフォルトのはず。

-f, --freeze

vender/railsRailsを凍結させる。
実行させるとvender/railsRails関係のファイルがまとまってコピーされる。
完成したアプリがRailsのverupなどで動作しなくなる、といったのを避けるためにRailsのverが固定できるぽい。

-v, --version

お約束のver表示。
ちなみに、うちの環境は「Rails 2.0.2」

-h, --help

これまたお約束のhelp表示。

-p, --pretend

実行するが変更は加えない。
要は雛形作成とかでエラーがでたりしないかのお試しぽい。
ディレクトリ・ファイル作成してるようにみえるが実際はなにも作成していない。

--force

すでに存在してるファイルを上書きする。
やり直したくなったときに強制上書きするのか?
そこまでするなら、それこそrailsコマンドで新しいアプリ作成したほうがいいような気もするが。

-s, --skip

すでに存在してるファイルをスキップする。
この場合のスキップは、上書き処理をスキップということだろうか?
--force同様、使う場面が思いつかない。

-q, --quiet

表示を避ける。
雛形作成時なんかにズラズラとファイル名を表示しなくなる。
表示はスッキリするがほんとに処理できてるのか不安になる。

-t, --backtrace

エラー時にバックトレースを出力してくれる。
railsコマンドでエラーなんて、ファイル書き込み権限の有無とかくらいしか思いつかないけども、どんなときに役に立つんだろ?

-c, --svn

Subversionを使ってファイルを修正する?
Subversion使ったことがないのでよくわからず。
大規模な開発だとうれしいのだろうか?

とりあえず、普段使いそうなoptionはなさげかな。

ひとまず1から動くところまで作ってみる

そろそろhelpとにらめっこするのも飽きてきたので、データベースを操作するところまで作ってみる。

まずは、ディレクトリを作成。

>rails test1

カレントディレクトリ移動。

>cd test1

でもって、scaffoldのgenerate。

>ruby script/generate scaffold item name:string price:integer
  • app/controllers/items_controller.rb
  • app/models/item.rb
  • app/views/items/index.html.erb
  • app/views/items/show.html.erb
  • app/views/items/edit.html.erb
  • app/views/items/new.html.erb
  • db/migrate/001_create_items.rb

その他もろもろが生成されてるのを確認。
もろもろは何に使うのかよく分かってないので、とりあえず放置。

次に、db/migrate/001_create_items.rb(migrationファイル)からデータベースを生成。

>rake db:migrate

SQLiteはファイルベースのデータベースなので、db/development.sqlite3というファイルが生成される。
デフォルトのdevelopment.sqlite3という名前が気に入らない場合は、config/database.yml内でファイル名は指定可能。

以上終了。

あとは、サーバを稼動させて挙動を見てみる。

ruby script/server

scaffoldでindexビューは生成されているので、ブラウザで「http://localhost:3000/items」につないで見ると、それっぽいのが表示される。

indexビューの、NewItemリンクからアイテムデータをもりもりと追加してあげると、

Name        Price
ポーション  100    Show Edit Destroy
毒消し      80     Show Edit Destroy
ナイフ      1000   Show Edit Destroy
ソード      2000   Show Edit Destroy

てな具合で登録される。

Showで詳細、Editで修正、Destroyで削除。
見た目はともかくこれだけでデータベースの管理が可能になるのは楽チン。

scaffoldをgenerateしてみる

とりあえず、コントローラとscaffoldがgenerateできれば、簡単なアプリなら作れそうかな?

scaffoldは、直訳すると「土台」
なんで土台か分からないけども、データベースへのレコード追加/削除/修正できるものが自動で生成されるらしい。

Rails2.0以降は、scaffoldのgenerateで、modelもmigrationも生成されるようなので楽になったらしい。
なにがどう楽になったのかはサッパリだけど、楽になってるなら楽な方を使っちゃう。

使い方は、

>ruby script/generate scaffold ModelName [field:type, field:type]

helpだと抜けているけども、optionは

>ruby script/generate scaffold [options] ModelName [field:type, field:type]

のモヨウ。

option

お約束の

  • -v, --version
  • -h, --help
  • -p, --pretend
  • -f, --force
  • -s, --skip
  • -q, --quiet
  • -t, --backtrace
  • -c, --svn

に加えて、

--skip-timestamps
自動で追加される作成日時・更新日時のfieldを追加しない
--skip-migration
migrationファイルを生成しない

といったoptionもある。

field:type

field
テーブルの項目
type
項目のタイプ

を、scaffoldをgenerateする時点で指定しないといけないらしい。
指定しなくてもエラーとかは出ないけど、中身のないtableがデータベースに作成されるだけ。
あとからfieldの追加はできるだろうけども、二度手間になるのでココで指定しちゃうほうが賢い。

具体的には、

name:string comment:text weight:integer ...

てな具合。
typeの種類はよくわからないけども、いろいろあるみたい。

scaffoldをgenerateすると、

  • コントローラー
  • ビュー
  • モデル
  • migrationファイル
  • その他もろもろ

が生成される。

generateのヘルプを読んでみる

初心者はまずはhelpから。

>ruby script/generate generator [options] [args]

てな具合で使う。

generator

イロイロあるようで、

controller
コントローラ&ビュー生成
integration_test
統合テスト生成?
mailer
メーラー&ビュー生成
migration
データベースのmigration生成?
model
モデル生成
observer
observer生成?
plugin
プラグイン生成?
resource
リソース関係のなんかを生成?
scaffold
scaffold生成
session_migration
意味不明(ノ∀`)

なんかがあるらしい。
controller/model/scaffoldあたりしか分からない。
ま、そのうち分かってくるでしょう。

あとなんかカスタムgeneratorなんてものも作れるモヨウ。
まあ、まずはBuiltinのgeneratorを使えるようになればいいので、そこらへんはあとの楽しみということで。

option

railsコマンドと似てる。

-v, --version
ver情報表示
-h, --help
help表示
-p, --pretend
実行するが変更しないコマンドテスト
-f, --force
強制上書
-s, --skip
スキップ
-q, --quiet
無言
-t, --backtrace
バックトレース
-c, --svn
Subversion

ちょっと気になったのが、forceオプション。
railsコマンドは「-f」がなかったのにgenerateコマンドには短縮名がある。

で、ちょっとrailsコマンドで-fオプションを使ってみると、

c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/core_ext/kernel/agnostics.rb:7:in ``': Exec format error - rake rails:freeze:gems (Errno::ENOEXEC)

なんてことを言われる。
ちなみに、--forceオプションは問題なく実行完了する。

generateコマンドは-fでも--forceでも問題なく実行完了するから、railsコマンドの-fオプションはなんかおかしいのかも?
素直に--forceオプションを使えってことだな。