2020年4月17日金曜日

Rails6 + PostgreSQL 超入門

概要

備忘録として Rails6 + postgresql の簡単なチュートリアル記事を残しておきます
Rails を久しぶりに使うときの導入記事として使いたいと思っています
ただバージョンによってかなり挙動や必要なツールが異なるのでその辺りはバージョンに応じて適宜対応してください

環境

  • macOS 10.15.4
  • Ruby 2.7.1p83
  • Rails 6.0.2.2
  • Postgres 12.2
  • nodejs 13.12.0

事前準備

  • gem install rails

グローバルにインストールしました
本当は bundle init してローカルインストールにしたかったのですがうまく動作しなかったので辞めました

PostgreSQL のインストールと起動

Postgres がまだインストールされていない場合はインストールしましょう

  • brew install postgresql
  • pg_ctl -D /usr/local/var/postgres start

停止したい場合は stop すれば OK です

  • pg_ctl -D /usr/local/var/postgres stop

nodejs/yarn のインストール

なぜか内部的に nodejs も使っているのでインストールします
webpack などの関係かなと思いますがとりあえず素直に入れます

  • brew install node
  • npm install -g yarn

新規アプリ作成

お決まりの TODO アプリになります
Postgres を使ったアプリを作成するので -d postgresql を忘れないようにしましょう

  • rails new todo -d postgresql

大量の gem がインストールされるので待ちます
スモールスタートしたいのにこの大量の gem をインストールするのがあまり好きになれないところでもあります

データベース作成

以下は作成したアプリのディレクトリ内で行います

  • cd todo
  • rake db:create RAILS_ENV=development

これで todo_developmenttodo_test というデータベースが作成されます
psql -l コマンドなどで直接 Postgres に問い合わせても確認できます

データベースをマイグレート

  • rails generate migration create_my_tasks

これでマイグレーションファイル db/migrate/20200415012753_create_my_tasks.rb が作成されるので編集します

  • vim db/migrate/20200415012753_create_my_tasks.rb
class CreateMyTasks < ActiveRecord::Migration[6.0]
  def change
    create_table :my_tasks do |t|
      t.string :title
      t.text :description
      t.timestamp :posted_date
      t.timestamp :updated_date
      t.boolean :public
    end
  end
end
  • rake db:migrate RAILS_ENV=development

これで todo_development データベース内に my_tasks というテーブルが作成されました

% psql todo_development psql (12.2) Type "help" for help.   todo_development=# \d my_tasks Table "public.my_tasks" Column | Type | Collation | Nullable | Default ————–+—————————–+———–+———-+————————————– id | bigint | | not null | nextval('my_tasks_id_seq'::regclass) title | character varying | | | description | text | | | posted_date | timestamp without time zone | | | updated_date | timestamp without time zone | | | public | boolean | | | Indexes: "my_tasks_pkey" PRIMARY KEY, btree (id)

新規モデル作成

作成した my_tasks テーブルを扱うモデルを作成します
すでにマイグレーションファイルは作成しているので --skip を指定します
g model はマイグレーションファイルも作成してくれるようなので g migration を実行しないで g model だけ実行しても良いと思います

  • rails generate model my_task --skip

app/models/my_task.rb が作成されれば OK です
test/models/my_task_test.rbtest/fixtures/my_tasks.yml はテスト用のファイルになります
ちなみにモデルは単数形で DB のテーブル名は複数形になります

コントローラ作成

実際に Web アプリのハンドリングを行うコントローラを生成します
my_tasks を CRUD するためのコントローラを作成しましょう

  • rails g controller my_tasks

ggenerate の省略形になります
慣れたら省略形を使ったほうが楽です

app/controllers/my_tasks_controller.rbapp/views/my_tasksapp/helpers/my_tasks_helper.rb が主なファイルになります
あとはスタイルシート用の .scss ファイルとテスト用のファイルも作成してくれます

routes.rb でルーティングを設定する

どの URL にアクセスしたらどのメソッドを実行するか定義します
ようやくこの辺りからプログラミングっぽくなってきます

  • vim config/routes.rb
Rails.application.routes.draw do
  get 'my_tasks', to: 'my_tasks#list'
  get 'my_tasks/:id', to: 'my_tasks#show'
  post 'my_tasks', to: 'my_tasks#create'
end

とりあえず今回は簡単な「取得」と「作成」だけ実装します
大抵の「更新」や「削除」なども必要になると思うので余裕があれば実装してみましょう

コントローラにルーティングされるメソッドを実装する

とりあえず一番簡単そうな list を実装してみましょう

  • vim app/controllers/my_tasks_controller.rb
class MyTasksController < ApplicationController
  def list
    @my_tasks = MyTask.order(posted_date: "DESC").all
  end
end

MyTask はモデルになります
コントローラからモデルの呼び出しは require 等は不要で参照できます
全件取得する場合は .all を使います
内部的には単純に SELECT * が実行されています

今回は order を使っていますが他にも様々な SQL 構文を実行できるので興味があればこちらのリファレンスを御覧ください

View を作成する

実際に HTML として出力されるテンプレートを作成します
先程コントローラで Postgres から取得した @my_tasks の情報を HTML として出力してあげます
また一覧から登録もできるようにするため form も設置しています
create メソッドは後述するためまだ動作はしません

メソッド名と同じ erb ファイルは所定の場所に配置すると自動的にそれを呼び出してくれるようです

  • vim app/views/my_tasks/list.erb
<html>
  <head><title>List My Tasks</title></head>
<body>
<h2>Create My Task</h2>
<form method="POST" action="/my_tasks">
  <p>Title: <input type="text" name="title"></p>
  <p>Description: <br><textarea name="description" rows="4" cols="40"></textarea></p>
  <p>Public: <input type="checkbox" name="public" value="checked"></p>
  <p><button type="submit">Create</button></p>
</form>
<h2>List My Tasks</h2>
<ul>
<% @my_tasks.each do |my_task| %>
  <li>Title: <a href="/my_tasks/<%= my_task.id %>"><%= my_task.title %></a> Posted Date: <%= my_task.posted_date %></li>
<% end %>
</ul>
</body>
</html>

とりあえず動作確認する

この状態でアプリは動作するようになっています
まだデータは何もないので特に表示はされませんが HTML がエラーなく出力されることを確認できると思います

  • rails server

localhost:3000 にアクセスすれば確認できます

post, show を実装する

残りのメソッドをコントローラに実装します

  • vim app/controllers/my_tasks_controller.rb
class MyTasksController < ApplicationController
  protect_from_forgery

  def list
    @my_tasks = MyTask.order(posted_date: "DESC").all
  end

  def show
    id = params[:id]
    @my_task = MyTask.find(id)
  end

  def create
    my_task = MyTask.new
    my_task.title = params[:title]
    my_task.description = params[:description]
    my_task.public = params[:public]
    my_task.updated_date = Time.now
    if my_task.public
      my_task.posted_date = Time.now
    end
    my_task.save
    redirect_to '/my_tasks'
  end
end

protect_from_forgery は CSRF (ActionController::InvalidAuthenticityToken) 対策になります
特に説明することはないと思いますが showparams[:id] を取得して特定の id のタスクの詳細を表示します

create は form から送られてきた情報を params から取得し MyTask モデルのインスタンスにセットします
あとは .save をコールすれば Postgres にデータが格納されます
格納後は /my_tasks にリダイレクトします

show.erb

詳細を表示するページも作成します

<html>
  <head><title>Show My Task</title></head>
<body>
<h2>Show My Task</h2>
  <p>ID: <%= @my_task.id %></p>
  <p>Title: <%= @my_task.title %></p>
  <p>Description: <%= @my_task.description %></p>
  <p>Posted Date: <%= @my_task.posted_date %></p>
  <p>Updated Date: <%= @my_task.updated_date %></p>
  <p>Public: <%= @my_task.public %></p>
</body>
</html>

動作確認

これで今回実装するべきすべての機能を実装しました
アプリを起動して動作確認してみましょう

  • rails server

localhost:3000 にアクセスすると以下のようにデータの登録から確認までができるようになっていると思います

最後に

Rails6 + PostgreSQL で超簡単な Web アプリを作成してみました
超入門レベルの流れは掴めたかなと思います
Controller と Model の連携方法、Controller からどうやって View が呼び出されるか変数が渡せるか、辺りを理解できれば OK かなと思います

Rails は実装よりも新規アプリ作成時のエラー対応の方が大変なイメージがあります

0 件のコメント:

コメントを投稿