データベース設計について

モデルとテーブル

Twitterのように、ユーザーが投稿した情報をHPのview上に反映させるサイトのことを動的サイトというが、これを作成するには、情報を保存する、またそれを引き出してviewに反映する仕組みが必要となる。その際に必要な考え方として「モデル」と「テーブル」がある。

まず、用語について簡単に説明を記述する。

テーブル

テーブルは、表の形式をした収納場所。データベースに複数存在し、それぞれのテーブルに情報を整理して保存する。

レコードとカラム

テーブルの横1行のことをレコード、縦1列のことをカラムという。

テーブルの条件

RailsによるWebアプリケーション用データの保存場所であるテーブルには、2つの特徴がある。 ①あるテーブル内のレコードを特定するための値として、idというカラムが与えられる。通常、idカラムには整数が入る。 ②行列によって区切られた1マスに入る値は1つでないといけない。

DB設計

アプリケーション開発においてほとんどのデータはデータベース内に保持される。アプリケーションは、言うなれば データの流通機構であり、どのようなデータをどういう形式で設計するかによって、品質は大きく左右される。 アプリケーション開発において、必要なテーブルやアプリケーションが快適に動作するように取り出しやすいデータベース構造をあらかじめ設計しておくことが必要となる。

※これは近年のソフトウェア開発での主流の考え方で、 DOA と言います。

DOA

DOAとは、 データ中心アプローチ(Data Oriented Approach) という考え方のこと。これは、プログラムよりも前にデータ設計から始める方法論のことを言う。DOAはサービス開発が効率的になるため近年主流になっている。

データベース設計の手順

データベース設計の手順は以下の通り。

①テーブルの抽出 ②テーブルの定義 ③テーブル構造を整理 ④ER図の作成

①テーブルの抽出

まず、アプリケーションにおいてあらかじめ最低限必要なテーブルを洗い出す。これにより、アプリケーションの開発中に新たなテーブルを慌てて作ることをしなくて済む。途中でテーブルを追加するとテーブル間の関係性を見直す必要が出て、また設計から見直さなくてはならなくなるので面倒である。

②テーブルの定義

テーブルを抽出した後は、各テーブルが持つカラムを決める。この段階でカラムを考える理由もテーブル抽出を行った理由と同様。こちらも、アプリケーションの開発中にカラムを追加すると、アプリケーションのコードを書き直したり、ビューのデザインを変えたりする必要があり、効率が悪い。

④テーブル構造を整理

テーブル構造にはアプリケーションのパフォーマンスを著しく下げるやってはならない構造がある。

A. 同じカラム名を1つのテーブルに複数作成

1つのテーブルに同じカラム名を複数作るようなテーブル構造になりそうになったら、必ず違うテーブルに保存するようにする。 以下は、記事に複数の画像を保存したい時の例です。

articlesテーブル

id title content image1 image2 image3
1 title1 ... photo1.png image1.jpg download1.png
2 title2 ... photo2.png image2.jpg download2.png
3 title3 ... photo3.png image3i.jpg download3.png

上記テーブル構造は悪例。これでは、記事に画像を追加する度にimageカラムを追加していかなくてはならない。 この場合、複数のimageに関するデータを1つのレコードが保持している状況。articles:1 に対して image:多 の関係が成り立っているので、テーブル間の1対多で表現できる。よって、以下のようにテーブルを分ける。

articlesテーブル

id title content
1 タイトル1 ...
2 タイトル2 ...
3 タイトル3 ...

imagesテーブル

id name article_id
1 photo1.png 1
2 image1.jpg 1
3 download1.png 1
4 photo2.png 2
5 image2.jpg 2
6 download2.png 2
7 photo3.png 3
8 image2.jpg 3
9 download3.png 3

これにより、imagesテーブルにレコードを追加していけば記事に画像を際限なく保存することができる。

B. 予約語について

データベースを作る際に一度はつまずいてしまうテーマに、「予約語」がある。 予約語とは、MYSQL側で使用されるためテーブル名やカラム名に設定することができないよう決められている単語のこと。 予約語をテーブル名やカラム名に含んでしまうとエラーになるので、予約語の一覧を確かめておく必要がある。

テーブルの関連付け

データベースに存在する複数のテーブルには関連付けがなされることが多い。

・1対多の関係 1対多とはつまり、ひとつのものに対して複数のものが紐付いているような状態。 1対多の関係性を作るには、 親子関係の子に当たるテーブルに、所属するモデル_id という規則でカラムを追加する。

例) usersテーブル(親)

id nickname email
1 sato sato@com
2 takahashi takahashi@com
3 yamada yamada@com

tweetsテーブル(子)

id title image text user_id
1 title1 photo1.png ... 1
2 title2 image1.jpg ... 2
3 title3 download1.png ... 1
4 title4 photo2.png ... 3
5 title5 image2.jpg ... 3

これまでが、Webアプリケーションの重要な構成要素のひとつであるデータベースについて。 以下で、Railsにおいてデータベースから情報を取得し利用する方法を確認する。

モデル

モデルとは、Railsの中でデータベースへのアクセスをはじめとする情報のやりとりに関する処理を担当しているパートで、実体は1つのクラスが定義された◯◯.rbというファイル。

モデルの使い方

基本的に、モデルはapp/models以下の階層に設置されます。

例)

class Sample

  def test
  end

end

Sampleというクラスが書かれているが、モデルを担当するクラスのことをモデルクラスと言う。例の場合は、Sampleというクラスがモデルクラスに当たる。

テーブルとモデルの結びつきは、名前で決定する

各種情報はテーブルに保存れ、Railsからあるテーブルに保存された情報を引き出す際は、そのテーブルに対応するモデルクラスを用意する。 対応関係は、テーブルとモデルクラスの名前によって決定する。

モデルの命名規則

Railsでは、ファイルやテーブルなどの命名を規則に従った形にする必要がある。モデルとテーブルに関する命名規則は以下のようになっており、これに従えばテーブルとモデルが結びつく。

種類 概要 名前例
モデルクラス名 先頭は大文字、単数形 Tweet
モデルクラスのファイル名 先頭は小文字、単数形 tweet.rb
テーブル名 先頭は小文字、複数形 tweets

Tweetクラスがtweetsテーブルを操作でき、モデルクラスが入ったファイル名はtweet.rbとなる。

モデルとテーブルの設計図を生成する

モデルとテーブルは1つのコマンドで同時に作成することができる。

rails g model コマンド

rails g modelコマンドを使用すると、DBにテーブルを作成するためのファイルとそのテーブルに対応するモデルファイルとを自動で作成することができる。実際に使用する際には「rails g model モデルクラス名(全て小文字)」というように作成したいモデルのクラス名を全て小文字にしたものを後ろに付けて実行する。

例) ターミナルにて

  $ rails g model モデルクラス名(全て小文字)
  # モデルを作成

rails d model コマンド モデルを作成する際は「rails g model」コマンドを使用下が、モデル名を間違えて作成してしまった場合、「rails d model」コマンドを使用してモデルファイルを削除することができる。

テーブルの作成

rails g modelコマンドでモデルのファイルを作成した際、同時にそのモデルと結びつくテーブルの設計図も生成されている。これをマイグレーションファイルと呼ぶ。 この段階ではまだ、DBには該当するテーブルは存在しなく、このマイグレーションファイルを実行することで、初めてテーブルが作られる。

マイグレーションファイル

マイグレーションファイルは、テーブルの設計図のようなもの。マイグレーションファイルにどんなカラムを持つテーブルにするかを記述し、実行することでテーブルが作成される。

※このマイグレーションファイルrails g modelコマンドを実行した際に作成されている。コマンド実行時にターミナルに下記のような表記がされるはずである。

create    db/migrate/20191005090000_create_tweets.rb

マイグレーションファイルの編集

マイグレーションファイルでは、changeというメソッドで、作成するカラムを指定することができる。

class Createテーブル名 < ActiveRecord::Migration[5.2]
  def change
    create_table :テーブル名 do |t|

      t.timestamps
    end
  end
end
カラムの「型」

カラム名を指定するとともに、そこにどんなデータが入るのかを示す「型」も指定する必要がある。 主な型の種類は以下の通り。

説明 用例
integer 数字 ユーザーidなど
string 文字(少) ユーザー名、パスワードなど
text 文字(多) 投稿文など
boolean 真か偽か 真偽フラグ
datetime 日付と時刻 作成日時、更新日時など

例)

  class CreateTweets < ActiveRecord::Migration[5.2]
    def change
      create_table :tweets do |t|
        t.string      :name
        t.text        :text
        t.text        :image
        t.timestamps null: true
      end
    end
  end

作成するカラムとその型を、changeというメソッドの中で指定する。 t.に続くのが「型」で、:に続くのがカラム名

マイグレーションファイルの実行

実際に作った設計図に従ってテーブルを操作するにはrake db:migrateコマンドを使用する。

rake db:migrate

現在存在している未実行のマイグレーションファイルを実行するコマンド。

スキーマファイル

スキーマファイルは、rake db:migrateを実行した際に更新が行われ、最新のマイグレーションファイルのバージョンが記録される。

schema_migrations

schema_migrationsとはデータベースの変更履歴のようなもので、どのマイグレーションファイルまでが実行されているかが記録されていくテーブル。マイグレーションファイルが実行された際に自動的に作成される。

※schema_migrationsを確認するために、Sequel Proを利用する。また、マイグレーションファイルは消してはいけない。実行し終わったマイグレーションファイルを削除してしまうと、schema_migrationsと齟齬が生じ問題が生じる恐れがあるためである。

※Sequel Pro Sequel Pro(シークエルプロ)は、テーブルを見やすく表示してくれるアプリケーション。データベースに接続し、見たいテーブルを選択するとエクセルのような形式で表示される。

一度変更したデータベースの状態を元に戻す

rake db:migrateコマンドを実行した際、読み込んだmigrationファイルの記述が間違っていて、意図しない名前や型を持つテーブルができてしまうことがあるが、そのような場合は、rake db:rollback コマンドを利用する。

※ 誤った名前のカラムを追加してしまった時は、実行したマイグレーションファイルを書き換えて再度 rake db:migrateすれば良いと思うかもしれないが、その方法では正しいカラムを作り直すことはできない。 なぜなら、railsではマイグレーションを一度実行してしまうと、そのマイグレーションを編集して再度マイグレーションを実行することができないためである。

rake db:rollback

これから先新たなテーブルを作成したり、カラムの追加などテーブルに変更を加える際は常にmigrationファイルを作成する。rake db:rollbackコマンドを実行すると、データベースの状態が最新のmigrationファイルを実行する前に戻ることになる。rake db:rollbackコマンドを実行すると最後に行われたマイグレーションファイルの実行が無かったことになるが、migrationファイル自体は残る。そのため、もう一度rake db:migrateコマンドを実行すれば再びテーブルが作成される。

テーブルの情報をRails側で利用する方法

あるテーブルに保存されているレコードの情報を取得するには、名前によって関連付ける必要がある。 例えば、tweetsテーブルに保存されているレコードの情報を利用するためにはTweetクラスを用意する必要があるが、rails g model コマンドでこれらを一度に生成できる。

テーブルと、関連するモデルクラスがある状態であれば、コンソール上から実際にコードを書いてテーブルの情報を取得する方法を試すことができる。 例)tweet = Tweet.find(1)

ActiveRecordの仕組み

なぜ定義されていないfindというメソッドが使えるのかということについてだが、実はrails g modelコマンドで生成されるモデルクラスは全てApplicationRecordというクラスを継承している。

ActiveRecord

ActiveRecord(アクティブレコード)はRubyのGemの一種。このGemはモデルとテーブルをつなぎ合わせることで、Railsからテーブルのレコードにアクセスできるようにする。ActiveRecordRailsにデフォルトでインストールされています。実際に、この機能を利用する際にはApplicationRecordというクラスを継承して使用する。ApplicationRecordというクラスにはテーブルにアクセスして情報を取得するためのメソッドが定義されており、モデルクラスはそれを継承し利用することでテーブルから情報を取得している。

クラスの継承

あるクラスに定義されたメソッドを、別のクラスで利用できるようにすることを継承と言う。

元となるクラスを親クラス、親クラスのメソッドを引き継ぎ新しく作成するクラスを子クラスとする。 クラスを継承した場合、親クラスで定義されているメソッドを子クラスで利用することができる。このとき継承元であるApplicationRecordで定義されているメソッドのことを「ApplicationRecordメソッド」と言う。ApplicationRecordはデータベースにアクセスするためのクラスなので、そのメソッドもデータベースへのアクセスを行うものになる。 以下にメソッド例をいくつか記す。

allメソッド

allメソッドはApplicationRecordを継承したモデルと結びつくテーブルのレコードを全て取得する。

newメソッド/saveメソッド

newメソッドはクラスのインスタンスを生成するメソッド。ApplicationRecordを継承しているモデルクラスの場合、newメソッドを実行すると関連するテーブルのカラム名がキーになったハッシュのようなものが生成される。これをモデルクラスのインスタンスと呼び、インスタンスのそれぞれのキーに値を代入してsaveメソッドを実行するとテーブルに保存される。

createメソッド

createメソッドはレコードの作成を行うことのできるメソッド。newメソッドとsaveメソッドを使用して行った処理をcreateメソッドで一気に行うことができるため、単にレコードを作成する場合にはこのメソッドを使用する。

SQL(エス・キュー・エル)

SQLとは、データベースに対して保存されているデータを要求する時に使用する言語形式。

本来ならデータベースに対しては以下のようなSQL文を使ってデータを要求しなければならないが、railsではActiveRecordのおかげで簡単にデータを要求することができる。

例1) SQL SELECT tweets.* FROM tweets

例2) [1] pry(main)> Tweet.all

上記の2つの例は同じ処理を行っている。Railsでは例2のように記述するだけで、データベースにアクセスする際には自動的に例1のようなSQL文に変換される。このように、ActiveRecordを使用するRailsではより直感的で短い記法でテーブルの情報を操作することができる。

レコードの更新

テーブルに保存されているレコードを更新するにはそのレコードをインスタンスとして取得し、カラムを指定して値を直接代入する。上書きするだけではレコードの値は更新されないので、上書きを保存するにはインスタンスのsaveメソッドを使う。