マイグレーションの様々な機能
まずテーブルを作成する前にカラムを追加できる型の種類を知っておく必要があるのではじめに主に使われるデータ型をまとめてみる。
データ型
データ型 | 説明 |
---|---|
:boolean | 真偽値 |
:integer | 符号付き整数 |
:float | 浮動少数点数 |
:string | 文字列(短い文字列に利用する) |
:text | 文字列(長い文字列に利用する) |
:date | 日付 |
:datetime | 日時 |
他にもたくさんあるが主に使われるデータ型をまとめた。
次にマイグレーションの代表的な個々のパターンについてまとめる。
新規テーブルを作成する
一番一般的なやり方だと思うが、モデルを作成することによって自動的にテーブルを作成する。
ここでは例としてFoodモデル(name属性を持つ)を作成してみる。
$ rails g model Food name:string
この結果
class CreateFoods < ActiveRecord::Migration[5.2] def change create_table :foods do |t| t.string :name t.timestamps end end end
Foodモデルを作成したことによってfoodsテーブルが作成され、カラムとしてname(string文字列)を追加するとを表している。
既存のテーブルにカラムを追加する
上記で作成したFoodモデル(foodsテーブル)に新しいカラムを追加します。
ここでは例としてdescription(string文字列)カラムを追加します。
すでにFoodモデル(foodsテーブル)を作成しているので、マイグレーションファイルだけrails g コマンドで作成する。
$ rails g migration add_description_to_foods description:string
上記のコマンドではrails g コマンドでマイグレーションを作成し、ファイル名は「addカラム名to_テーブル名」とし、そのあと追加するカラムを指定している。
この結果、
class AddDescriptionToFoods < ActiveRecord::Migration[5.2] def change add_column :foods, :description, :string end end
add_columnメソッドを使用してfoodsテーブルにdescriptionカラムが追加されていることがわかる。
既存のテーブルのカラム属性を変更する
descriptionカラムを追加したが複数行の文字列に対応させたいとします。現在の属性タイプではstringで複数行の文字列にはふさわしくないのでtextタイプに変更しなければいけない。
このような場合に変更するための適切な名前のルールはない。ここではchange_datatype_description_of_foodsといいう名前のマイグレーションファイルを作成する。
$ rails g migration change_datatype_description_of_foods
ここではオプションを設定していないので下記のようなマイグレーションが作成されていることがわかる。
class ChangeDatatypeDescriptionOfFoods < ActiveRecord::Migration[5.2] def change end end
このマイグレーションファイルにカラムを変更するための記述を行う。
カラムの変更を行うにはchange_columnメソッドを使用する。
change_columnの後にモデル名、テーブル名、変更する属性とする。
class ChangeDatatypeDescriptionOfFoods < ActiveRecord::Migration[5.2] def change change_column :foods, :description, :text end end
これでfoodsテーブルのdescription属性タイプをtextに変更することができる。
他にも色々な方法でマイグレーションの設定ができるが基本的なテーブルの作成、カラムの追加、カラム属性の変更ができるようになった。
マイグレーションのメソッド
上記でテーブルの作成、カラムの追加、カラム属性の変更ができるようになったがもっと柔軟にマイグレーションが扱えるようにマイグレーションのテーブルを操作するメソッドやテーブル操作の中で使用できるメソッドをまとめてみる。
マイグレーションのテーブル操作メソッド
メソッド | 役割 |
---|---|
change |
テーブルの作成、カラムの追加、削除を行う場合に使用する。最も利用されるメソッド |
up |
rollbackが働くよう、スキーマに対する変更を記述する。up(変更記述) / down(戻し記述) |
down |
rollbackが働くよう、upメソッドによって追加されたスキーマの変更を「元に戻す」方法を記述する。up / downは対になって利用される |
reversible |
changeメソッドだけで簡単にマイグレーションのロールバックを判定できないような場合に、up / downを使用して「変更」と「戻し」の処理をreversibleの中に取り込み、どちら向きの変更処理でも常に同じ方向の処理ができるようにする |
revert |
実行済みのマイグレーションの一部のみをロールバック(元に戻す)場合に使用する。戻したい実行済みのマイグレーション記述をコピーし、revertブロック野中に組み込むことでロールバックを実現する |
テーブル操作メソッドの中で使用できるメソッド
メソッド | 構文 | 役割 |
---|---|---|
create_table | create_table :テーブル名 [, オプション] | テーブルを作成する |
drop_table | drop_table :テーブル名 [, オプション] | テーブルを削除する |
rename_table | rename_table :現在のテーブル名, :新しいテーブル名 | テーブル名を変更する |
change_table | change_table :テーブル名 [, オプション] | テーブル設定を変更する |
add_column | add_column :テーブル名 :カラム名, :データ型 [, オプション] | カラムを追加する |
add_reference | add_reference :テーブル名, :リファレンス名 [, オプション] | 外部キーリファレンスを追加する(親子のアソシエーションで使用可能) |
add_timestamps | add_timestamps :テーブル名 | タイムスタンプ(登録日、更新日を追加する) |
rename_column | rename_column :テーブル名, :変更するカラム名, :新しいカラム名 | カラム名を変更する |
change_column | change_column :テーブル名, カラム名, :データ型 [, オプション] | カラム設定を変更する |
remove_column | remove_column :テーブル名, :カラム名 [, :データ型, オプション] | カラムを除去する |
remove_reference | remove_reference :テーブル名, リファレンス名 [, オプション] | 外部リファレンスキーを除去する |
remove_timestamps | remove_timestamps :テーブル名 | タイムスタンプ(登録日、更新日)を除去する |
add_index | add_index :テーブル名, :インデックスを付与するカラム名 [, オプション] | インデックスを追加する |
rename_index | rename_index :テーブル名, :旧インデックス名, :新インデックス名 | インデックス名を変更する |
remove_index | remove_index :テーブル名 [, オプション] | インデックスを削除する |
まとめ
モデルの作成は簡単だが、マイグレーションファイルのみ作成し、自分でカラムを追加したり削除したりすることはあまりやってなかったのでこれで理解できるようになった。
すべてのメソッドを使いこなせるにはまだまだ時間がかかりそうだが、柔軟にマイグレーションファイルを使いこなせるようにしていきたい。
現場Railsで唐突に出てきたメソッドの理解
Railsを勉強している人なら誰しもがわかる技術書「現場で使えるRuby on Rails速習実践ガイド(以下、現場Rails)」にて勉強していたらRailsチュートリアルでも見たことのないメソッドが出てきて、 「現場で使われるということはこういうことか...」とか勝手に思った。
どのようなメソッドだったのか。
simple_formatメソッドである。(そんなん知ってるわ、って思っていたらすみません)
現場RailsのChapter3-3で出てくる。現場Railsによると、
simple_formatはデフォルトエリアを
タグで囲い、テキストに含まれる一部の危険なHTMLタグを取り除いてくれます(=sanitizeオプション)。
しかし今回は一部のタグを取り除くのではなく、すべてのタグを安全な形で表示することにします。〜以下略
と書いてある。しかしよくわからない。
テキストに含まれる一部の危険なHTML?!
これは調べないとわからない。。Railsドキュメントでググってみよう。
説明
- 文字列を
<p>
で括る。 - 改行は
<br/>
を付与。 - 連続した改行は、
</p> <p>
を付与。
使い方
simple_format(文字列 [, オプション or HTML属性 or イベント属性])
オプション
オプション | 説明 |
---|---|
:sanitize | サニタイズ |
:wrapper_tag | 文字列を囲むタグ |
イベント属性
イベント属性 | 説明 |
---|---|
:onclick | クリックされた時 |
:ondblclick | ダブルクリックされた時 |
:onmousedown | マウスのボタンが押し下げられた時 |
:onmouseup | マウスのボタンが離された時 |
:onmouseover | カーソルが重なった時 |
:onmousemove | カーソルが移動した時 |
:onmouseout | カーソルが離れた時 |
:onkeypress | キーが押されて離された時 |
:onkeydown | キーが押し下げられた時 |
:onkeyup | キーが離された時 |
例
<% text = <<EOL テキスト テキストテキスト EOL %> <%= simple_format(text) %> # <p>テキスト</p> # <p>テキストテキスト</p>
simple_formatの概要は理解できた。では一体なぜこのようなメソッドがあるのか。
冒頭で?になっていたテキストに含まれる一部の危険なHTMLタグを取り除くということがこのメソッドの特徴である。
sanitize(サニタイズ)とは
サニタイズ(Sanitize)とは、危険なコードやデータを変換または除去して無力化する処理です。 たとえば、Webサイトに設置された入力フォームなどから、悪意のあるコードが入力され、その文字列が実行されることで様々な被害に遭う可能性があります。この入力値に対しサニタイズを行い、悪意のあるコードを無力化(単なる文字列として扱う)することで、被害を阻止することができます。 サニタイズ(Sanitize) | セコムトラストシステムズのBCP(事業継続計画)用語辞典より
では度々危険なHTMLタグや危険なコードと言っているが危険な〜とはどういうことなのか。
クロスサイトスクリプティング(XSS)という、攻撃対象のウェブサイトに、脆弱性がある掲示板のようなウェブアプリケーションが掲載されている場合に、悪意のある第三者がそこへ罠を仕掛け、サイト訪問者の個人情報を盗むなどの被害をもたらす攻撃が危険ということがわかった。
クロスサイトスクリプティング(XSS)については上記の記事でわかりやすく図を使って説明されているので掲載しておく。
また→XSS攻撃体験サイトでは実際にクロスサイトスクリプティング(XSS)が体験できるサイトなのでどういうものなのか体感できます。
まとめ
初めてsimple_formatの説明を現場Railsで読んだときは危険ななんとかかんとかってなんやねん!って思ってましたが、クロスサイトスクリプティング(XSS)という攻撃があり、これがどのような危険があるかということを知ることができ、セキュリティ面で非常に活躍するメソッドなんだなということがわかった。WEBアプリケーションでセキュリティは一番大事といっても過言では無いと思うので、simple_formatメソッドを使いこなせるようにしていきたい。
モデルを作ってrails db:migrateしようとしたらエラーに遭遇した件
タイトルのままなんですが、、、 一応開発環境とかも説明しておく
開発環境
マイグレーションファイル
モデル名 Task
テーブル名 tasks
カラム name:string
description:text
どのようなエラーが出た?
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::DuplicateTable: ERROR: relation "tasks" already exists
英語が苦手というわけではないが、すらすら読めるわけではないので便利な「Deel」という翻訳アプリを使って翻訳してみた。
レールは中止されました !
エラーが発生し、これ以降のすべての移行がキャンセルされました。
"tasks" リレーションが既に存在する。
うーん。なるほど。多分めんどくさい。
マイグレーションファイルに問題がありそうなので、
rails db:migrate:statusコマンドでマイグレーションファイルの状態を確認してみよう。
database: taskleaf_development Status Migration ID Migration Name -------------------------------------------------- up 20201228122412 ********** NO FILE ********** up 20201230060553 ********** NO FILE ********** up 20201230061636 ********** NO FILE ********** up 20201230094313 ********** NO FILE ********** up 20201230095352 ********** NO FILE ********** up 20201230150314 ********** NO FILE ********** down 20210106145728 Create tasks
!?!?!?!?!?明らかにおかしい... まずこのNO FILEのマイグレーションファイルを全部削除して再度rails db:migrationを実行することにしようか。
上記の記事を参考にして、一度マイグレーションファイルをすべて削除し、綺麗な状態に戻そう。
再度 rails db:migrate:statusコマンドを叩き、
database: taskleaf_development Status Migration ID Migration Name --------------------------------------------------
この状態にしたらrails g model Task name:string description:text を実行し、rails db:migrateを実行してみる。
んんん???エラーが治らん...
マイグレーションをリセットするのを忘れてしまっていた。
rails db:migrate:resetを叩き、
rails db:migrate:statusを見てみると、
database: taskleaf_development Status Migration ID Migration Name -------------------------------------------------- up 20210106154208 Create tasks
しっかり動きました。
まとめ
マイグレーションファイルやデータベースはRailsと別の世界にあるので、データベースの世界にカラムが残ってたり、マイグレーションファイルを消しても内部で NO FILE みたいに残っていることがある。 焦らず、rails db:migrate:statusで、マイグレーションの状態を確認し、不要なファイルがあれば、削除。再度リセットする。ということを頭に入れて置くことが大事だと感じた。
〜完〜
Rails国際化(i18n)を簡単に導入する
Railsにはよくあるエラーメッセージがerrorsメソッドで呼び出される。 デフォルトの状態では英語での出力となっているため、日本語に対応させる必要がある。 簡単に日本語対応するには2つのステップで対応させることができる。(他にもやり方は色々あるが、自分がやりやすいやり方で紹介する)
ステップ1
$ wget https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -P config/locales
ターミナルでこのコマンドを叩く。
コマンドのオプションに関してはLinuxの範囲になるので、詳しくは割愛するが、
wgetコマンド + URLを指定することによってそのURLのファイルをダウンロードすることができる。
実際にhttps://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.ymlにアクセスしてみるとわかるが、i18nの日本語ymlファイルがある。
また、-Pオプションで保存先となるディレクトリを指定することができる。つまり、configディレクトリ内のlocalesディレクトリにja.yml ファイルがダウンロードされている。
--- ja: activerecord: errors: messages: record_invalid: 'バリデーションに失敗しました: %{errors}' restrict_dependent_destroy: has_one: "%{record}が存在しているので削除できません" has_many: "%{record}が存在しているので削除できません" date: abbr_day_names: - 日 - 月 - 火 - 水 - 木 - 金 - 土 abbr_month_names: - - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 day_names: - 日曜日 - 月曜日 - 火曜日 - 水曜日 - 木曜日 - 金曜日 - 土曜日 and more...
詳しくは↓のページに色々書いてるので参考に。 www.atmarkit.co.jp
ステップ2
あとはデフォルトで日本語のコンテンツを使うようにアプリケーションの設定を変更する。 config/initializersディレクトリにlocale.rbというファイルを作って
Rails.application.config.i18n.default_locale = :ja
とすることで、Railsアプリケーションのエラーメッセージなどを日本語化することができる。