💡

Django使いがキャッチアップのためにRails(+Docker)を触ってみた(#1 環境構築編 2022年)

2022/06/04に公開

はじめに

本記事の目的

初めてwebアプリフレームワークを学ぶにあたってMTVモデルであるDjango(Python)を選んだ筆者が、Djangoと適宜比較しながらMVCモデルであるRuby on Railsをキャッチアップする

なぜ本記事を書こうと思ったのか

特にプログラミング歴が浅い人にとって、学習するにあたってどの言語・フレームワークを選ぶかということは多少悩むことがあると思います(筆者だけ?だいたいはバックエンドを学ぶなら初学者はひとまずRails選ぶことが多い?)
私自身もフレームワークを選ぶにあたって、当時比較検討をした上で以下の点でひとまずDjangoを学ぶことを決めました

  • フレームワークを学ぶ以前に多少触っていた言語であったPythonにある程度慣れていたため
  • 自分がプログラミングを始めるきっかけにデータ分析やスクレイピングに興味あり、それらを行う候補筆頭でよくPythonが上がっていたため
  • Pythonで候補によくあがるWebフレームワークにおいては、Djangoが一番日本語文献が多そうで学びやすいと思ったため
    (他候補にFlaskなど。当時はAPIとして使用することなどの知識もなかったです)
  • RailsのMVCモデルとDjangoのMTVモデルにある程度の類似性があると思われたことから、どちらか一つを理解すればもう片方のキャッチアップも行いやすいと考えたから

↑一番の理由はこれです。正直国内でのRailsとDjangoの使用比率ではRailsの方が多いと思われることからも、Djangoをある程度学んだ途中でRailsに切り替えようかと一度真剣に考えました。
ですが途中で切り替えてどちらの言語も習得が中途半端になるのはよくないと思いDjangoを継続した経緯があります。

上記を踏まえて、本記事を書こうと思った理由は、
「Djangoをある程度学べば、Railsのキャッチアップも比較的に行いやすいだろう」という自分の仮説を検証するためになります。
(細かいことを言えば、両フレームワークさらにはPython/Rubyの仕様の良し悪し・個人的趣向等がそれぞれあるかと思いますが、その点はご容赦いただければ・・・)

本記事を読み進めるにあたっての前提

筆者は

  • Djangoの使用歴は1年ちょい
  • 現在のDjangoの使い方としては、半分はDjango REST frameworkとしてバックエンドのAPIとして使用しているため、フルスタックでの使い方には疎いです

(正直全容をしっかり理解しているとは到底言えないので、もっといい案あるなどのご指摘がありましたら是非コメントいただければ幸いです)

開発環境

  • OS:Windows 11(WSL2使用:Ubuntu-20.04)

Rails(+Docker)を触ってみた(#1 環境構築編)

長い前置きから最初は環境構築のみだけか?というツッコミありそうですが、思ったよりハマった点が何か所かあったので書きます。
環境構築はローカル環境を汚さなくて、手軽にコンテナを作って壊せるDockerで行います。

  1. imageを作成するために以下4ファイルを用意
  • Dockerfile
  • docker-compose.yml
  • Gemfile
  • Gemfile.lock

ディレクトリ構造は以下にします
(アプリケーションは別途フォルダ以下に配置するのが好み)

directory
.
|--rails-app/ #アプリ名
|    |--Dockerfile
|    |--Gemfile
|    |--Gemfile.lock
|--docker-compose.yml

①Dockerfile

Dockerfile
FROM ruby:2.7

ENV LANG=C.UTF-8 \
    TZ=Asia/Tokyo

RUN apt-get update -qq && apt-get -y install \
    build-essential \
    libpq-dev \
    nodejs \
    default-mysql-client

# RUN apt-get install yarn
# 上記でインストールするとエラーが出るため公式のインストール方法で最新のyarnをインストールする
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn

RUN mkdir /code

COPY Gemfile /code/
COPY Gemfile.lock /code/

WORKDIR /code

RUN gem install bundler && bundle install

rubyのversionは今回立ち上げからRailsの基礎のキャッチアップのためひとまず2.7を選びました

*** ハマりポイント1 ***
Rails6からはwebpackを使用するのでNode.js Yarnをインストールする必要があるようです
そのため、Yarnをインストールするのですが素直にapt-get install yarnにすると、Railsアプリ作成時に以下エラーができました

rails aborted!
ArgumentError: Malformed version number string 0.32+git

そのため、安定版で最新のyarnをインストールするようにDockerfileを下記のように変更する必要がありました

Dockerfile
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn

参考【Rails】ArgumentError: Malformed version number string 0.32+gitでwebpacker:installが実行できない場合の対処方法

②docker-compose.yml

docker-compose.yml
version: '3'
services:
  db:
    container_name: mysql
    image: mysql:5.7
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - mysql_testdata:/var/lib/mysql/
    ports:
      - '3306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: password
    # env_file:
    #   - ./.env #環境変数は別途.envファイルで管理する方が好み
  rails-app:
    container_name: rails-app
    build:
      context: ./rails-app/
    volumes:
      - ./rails-app:/code #docker-compose.ymlを位置から見て指定
    command: bundle exec rails s -p 3000 -b '0.0.0.0' #最初railsアプリ作成する際はコマンドアウトする
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
volumes:
  mysql_testdata:

(dockerファイルは設定忘れやすいのでコメントアウトが多め、適宜無視してください)

この辺はRails固有の設定はないですね

③Gemfile

Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"

bundle initで生成してもいいし、上記をコピーしてもいいですかね

④Gemfile.lock

Gemfile.lock

空でOK


脱線:Pythonと比較して
この辺は一度理解すれば、特に差はなさそうですね
今回の本題とは逸れますが、RubyではDockerを用いつつbundle及びGemfile&Gemfile.lockでパッケージ管理できそうな点が良さそうです(要確認)
Pythonでもpipenv及びPipfile/Pipfile.lock等があるようですが、Dockerと併用する際にはpipenvの仮想環境周りで結構やりくりしなくてはいけないために、導入を断念した経緯があります


  1. アプリ作成
docker-compose up -d --build

image及びコンテナを作成

※ここでdocker-compose.ymlの

command: bundle exec rails s -p 3000 -b '0.0.0.0'

部分は初回コンテナ作成時にはRailsアプリを作成していないためおそらくSTOPしてしまうからコメントアウトしておくといいと思います(もっとうまい方法あるのかもしれないが・・)

docker exec -it rails-app bash

コンテナ起動したら、コンテナ(rails-app)内に入ってRailsアプリを作成します

※慣れている方でしたら、コンテナ内に入らずにターミナルから直接docker container exec -it rails-app xxx~で操作してもいいですが、慣れてない場合はコンテナ内に入って操作したほうがわかりやすいです

root@32ec20234276:/code# rails new . --force -d mysql
root@32ec20234276:/code# rails s -p 3000 -b '0.0.0.0'

アプリ作成します、その後サーバー起動して特に問題なければ立ち上がると思います

*** ハマりポイント2 ***
記事によってはオプションで--skip-bundleを入れているものもありましたが、
--skip-bundleを入れた場合、RailsでViewを表示させる際に以下エラーに悩まされました
(bundle installスキップし後ほど実行するのでもOKかなと思っていましたがダメでした)

Webpacker::Manifest::MissingEntryError

ようはWebpackerがインストールされていないのですが、Node.js Yarnのバージョンを確認したり、rails webpacker:installを実行したり、と試してみたのですがうまくいかなかったので素直に外したほうがいいかと思います。

  1. DBの設定・アプリ立ち上げ

初回立ち上げ時にはDBの接続設定・DB作成を行っていないのでdatabase.ymlを設定していきます

config/database.yml
default: &default
 adapter: mysql2
 encoding: utf8mb4
 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
 username: root
 password: password #docker-compose.ymlで設定した環境変数のパスワードを設定
 host: db #docker-compose.ymlで設定したサービス名にする
  • MySQLのパスワードをdocker-compose.ymlで設定した環境変数のパスワードを設定
  • hostをdocker-compose.ymlで設定したサービス名にします
    hostをサービス名にするあたりの名前空間については気になる方は以下の記事がわかりやすいです
    参考Docker Compose入門 (4) ~ネットワークの活用とボリューム~

もしファイルを更新しようとして、エラーが出た際はファイル・ディレクトリの所有者とグループがrootになっている可能性があるので、chownコマンドで自身に変更してください

コンテナ外のターミナル
ls -l #ファイル・ディレクトリの所有者、所有グループ、パーミッション等詳細表示

sudo chown -R user:group rails-app #user:groupの部分は新しく作成したrails-app以外の表示部分に合わせればひとまずは問題ないです

ls -l #所有者、所有グループが変わったか確認、他と同じになれば大丈夫です

database.ymlの設定を終えたら、マイグレーションファイル作成・DB作成を行っていきます

root@32ec20234276:/code# rails generate scaffold User name:string
root@32ec20234276:/code# rails db:create
root@32ec20234276:/code# rails db:migrate

ここでlocalhost:3000にアクセスして以下表示されればRailsアプリ作成です
Yay! You're on Rails!

次に先ほどrails generate scaffold User name:stringでUserモデルを作成したので、
localhost:3000/usersにアクセスしてエラーが生じなければWebpackerの問題もクリア出来ています(データ自体は入れていないので表示データはありません)


Djangoと比較して
この辺もDjangoとは流れはほぼ同じです
アプリ作成→DB周りの設定→マイグレーションファイル作成・DB作成
Railsで驚いたのがModel・View・Templete(RubyでいうModel・Controll・View)を一括で作成してくれるコマンドが標準であるのは便利だなと感じました
(Djangoではルーティングやモデルそれぞれで設定していました)
→Djangoにもgenerate scaffold的なコマンドで一括に作成できないか軽く調べたら、
同じようなコマンドで作成できるdjango-generate-scaffoldという外部ライブラリはあるそう


終わりに

もともと環境構築で記事を作成するつもりはなく、案の定DjangoとRailsの比較についてはあまり比べられなかったのですが、Rails+Dockerでの構築に思ったより手こずって備忘録のためにも書きました。
いろいろ記事等を読み比べしますが、Versionの違いだったりもあり、微妙に内容が異なっていたり等してうまくいかないことがあったので、誰かの助けになれば幸いです。

今後の予定としては、当初予定していたDjangoとRailsの比較も踏まえた以下の項目を取り上げながらRailsをキャッチアップしつつ、DjangoとRailsおよびPythonとRubyの特徴・良し悪しなどを考察しながら、フレームワーク・言語仕様についての理解を深めていければと思います。

  • DjangoとRailsの記法の違い(MVT-MCV周りなどの基礎)
  • DjangoとRailsの細かい違い(ORM周りの記法など)
  • Django REST FrameworkとRails APIモードの違い
  • PythonとRubyの記法の違い

※細かいところを考えると、外部ライブラリ等も絡んできて、両者得手不得手等出てくるかと思うので基礎的なところ周辺を考えています。

22/6/5追記
第2弾書きました
DjangoとRailsの記法について比較してみた #2

Discussion