ActiveRecord を色々試せる環境を作ってみる

こんにちは。ryohei515です。

実務で ActiveRecord の動作を確認したいときは、開発環境内の Rails Console で動かしてみるのですが、プライベートで確認したい時用に環境を作っておきたいと思い、備忘録的に残しておきます。
過去の記事で、サンプルデータを使って DB を触れる環境を作ってみたので、今回はそれを Rails から触れるようにしようと思います。

1. データ準備

以下のサンプルデータを使用します。データがほどよくあるので便利です。
PostgreSQL Sample Database

ダウンロードしたファイルは unzip コマンドで解凍しておきます。

unzip ./dvdrental.zip

2. Docker関連のファイルを作成

Docker の公式サイトを参考に、Rails の環境を構築してみます。
クィックスタート: Compose と Rails — Docker-docs-ja 19.03 ドキュメント

ただ、掲載の Rails, Ruby のバージョンが少し古いので、こちらを参考に、Rails は 6.1.6、Ruby は 2.7.6 を利用するようにします。

適当にディレクトリを作成して、以下の4ファイルを配置します。

docker-compose.yml

version: '3.8'
services:
  db:
    image: postgres:14.2-alpine
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

volumes:
  db-data:

Dockerfile

FROM ruby:2.7.6
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs yarn
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

Gemfile

source 'https://rubygems.org'
gem 'rails', '~> 6.1.6'

Gemfile.lock

(空ファイルで作成しておく。)

3. Rails プロジェクトを作成

以下のコマンドを実行して、ディレクトリを作ります。

docker-compose run --rm web rails new . --force --database=postgresql

4. データを DB に反映させる

3 の手順により、DB のコンテナが立ち上がったままとなっているので、起動させたコンテナのIDを特定し、ファイルをコピーします

docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED             STATUS             PORTS                    NAMES
ce4299b2c1c6   postgres:14.2-alpine   "docker-entrypoint.s…"   About an hour ago   Up About an hour   0.0.0.0:5432->5432/tcp   rails-docker-trial_db_1

docker cp /tmp/dvdrental.tar ce4299b2c1c6:/

起動中の DB コンテナに入り、コピーしたファイルをDBに復元させます。

dc exec db bash

bash-5.1# psql -h localhost -U postgres -c "CREATE DATABASE dvdrental;"
bash-5.1# pg_restore -h localhost -U postgres -d dvdrental ./dvdrental.tar

これでサンプルデータが DB に反映された状態になりました。

ただこのサンプルデータには、 独自に追加された型定義があるため、このままだと Rails 側でスキーマ情報を反映させた時エラーとなります。
そのため、その独自の型定義を使用している、film テーブルの rating を String に置き換えます。
(View でも利用されており、View を削除しないと型定義が変更できないため、先に削除します)

psql -h localhost -U postgres -d dvdrental

psql (14.2)
Type "help" for help.

dvdrental=# DROP VIEW film_list;
DROP VIEW

dvdrental=# DROP VIEW nicer_but_slower_film_list;
DROP VIEW

dvdrental=# ALTER TABLE film ALTER COLUMN rating TYPE varchar(255);
ALTER TABLE

dvdrental=# ALTER TABLE film ALTER COLUMN rating SET DEFAULT 'G';
ALTER TABLE

5. Rails から DB にアクセスできるようにする。

config/database.yml は以下のように記載しておきます。

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: dvdrental

test:
  <<: *default
  database: dvdrental_test

その後、web コンテナに入り DB の定義から db/schema.rb を作成します。

docker-compose run --rm web bash

root@90f53214db3a:/myapp# bin/rails db:create
root@90f53214db3a:/myapp# bin/rails db:schema:dump

あとは存在するテーブルの model を作成し

bin/rails g model film --migration=false

(Rails の命名規則に従ったテーブル名ではないため)作成した model にテーブル名を指定してあげれば、Rails Console から扱えるようになります。

class Film < ApplicationRecord
  self.table_name = 'film'
end
bin/rails console
Running via Spring preloader in process 90
Loading development environment (Rails 6.1.6)
irb(main):001:0> Film.first
  Film Load (1.8ms)  SELECT "film".* FROM "film" ORDER BY "film"."film_id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<Film film_id: 1, title: "Academy Dinosaur", description: "A Epic Drama of a Feminist And a Mad Scientist who...", release_year: 2006, language_id: 1, rental_duration: 6, rental_rate: 0.99e0, length: 86, replacement_cost: 0.2099e2, rating: "PG", last_update: "2013-05-26 14:50:58.951000000 +0000", special_features: ["Deleted Scenes", "Behind the Scenes"], fulltext: "'academi':1 'battl':15 'canadian':20 'dinosaur':2 ...">

おわりに

全 model で自動的にうまくテーブル名をつけたかったですが、今回はここまでです。
これを利用すれば、既存の DB に、Rails で接続して利用する時もできるようになりそう。
このサンプルデータは程よくデータが格納されているので、これでプライベートでも色々試せそうだなと思いました。

インゲージではエンジニアを募集中です!
詳細は以下のリンクよりご確認ください!

ingage.co.jp