Ruby on Rails ~レールの路線図~ Part 1 [Ruby3, Rails6]

2006.1.21 に Rubyist九州 Meeting 第1回にて発表した, Ruby on Rails のスライドです。2005年12月に Rails 1.0 が出ました。その前後, 同月に初めて Railsに触ったので、まだほんの初歩的、序の口のところです。http://jp.rubyist.net/?rubyist-kyushu-memo01 リンク切れ

[2021.5] ざっと現代の状況に更新。Ruby 3.0 + Ruby on Rails v6.1. サンプルコード netsphere / rails-examples · GitLab

  1. このページ. アプリケィションひな形の起動まで。
  2. ページ2 最初のDBアプリケィションづくり。
  3. ページ3

はじめに

21st Jan 2006

堀川 久 https://www.nslabs.jp/

[2021.5] Webアプリケーション開発に Ruby on Rails が果たした役割は非常に大きい。バージョン1.0.0 リリースが2005年12月。そこから15年以上経っているが、まだ現役。さらに、後続の様々なWebアプリケーションフレームワークのデザインにも多大な影響を与えた。

現代では、ユーザ接点であるフロントエンドを単純な HTML で書くのは, 考えられない。React (JavaScript) がよい。それでも, BFFパターン (Backend for Frontend) として、バックエンドを Ruby on Rails で作る、というのはよい考え。

Ruby on Rails は、どちらかというと少人数のチームに適したフレームワークで、いかに素早く機能を追加していくか、開発の生産性にフォーカスしている。実行速度は重視していない。サーバリソースを突っ込めばいいという割り切り。

フロントエンドと合わせて, バックエンドも JavaScript で作るというアイディアもある。Express v4, その後継の Koa v2 が有力。しかし、実際に試してみたが, Rails に比べて生産性は非常に低い。お勧めできない。

実行速度 (スループット; 単位時間当たりの処理件数) を重視してサーバを節約するなら, C++, Actix (Rust), Java, ASP.NET Core (C#), Go あたりが優勢。C++ でWebアプリケーションは書きたくない。ASP.NET Core 5.0 はなかなか良い。

ここでは, 概略のために, フロントエンドもバックエンドも Ruby on Rails を使う例を示す。

[/2021.5 ここまで]

これまでの私

1.Ruby添付の cgi-lib.rb

2.Ruby添付の cgi.rb

3.テンプレートエンジンの探索

4. 現在:

  • Ruby/DBI ... http://rubyforge.org/projects/ruby-dbi/ [リンク切れ] Ruby/DBI は完全に廃れた. 'activerecord' 一強。
  • amrita-altered ... https://www.nslabs.jp/amrita-altered.rhtml 過去との互換性のために維持。現代は ERB テンプレートを使う。メジャーなのは 'erubi' だが、機能性が不足 ('tilt' と組み合わせる前提). 単独なら 'erubis' のほうがよい。
  • コントローラ ... 昔は Struts に似たものを自作していた。今は単に Rails でよいと思う。

よいチュートリアル

Tutorial in Ruby on Rails http://wiki.rubyonrails.com/rails/pages/Tutorial サイト消失. Ruby on Rails Guides (v6.1.3.2)

しかし、Railsの全体像をつかまないと、自分でアプリケーションを書けません。

試した環境

  • Fedora Linux 34
  • SQLite

[2021.5] Ruby on Rails アプリケーションを動かすには、次のソフトウェアを用意する。

  1. Ruby. これがないと始まらない. ヴァージョン 2.7.2 以降か、v3.0 がよい。
  2. RDBMS. MySQL or MariaDB はおそらく廃れつつある。最近聞かない。PostgreSQL か, あとは商用で Oracle Database か Microsoft SQL Server ぐらいか。手許で試すだけなら SQLite も使える。
  3. HTTP サーバ. Apache HTTP Server も廃れつつある、かな。私 (堀川) は Nginx を使っている。
  4. アプリケーションサーバ. HTTPサーバに組み込むか、別に動かす。

    私は Passenger を使っているが, Ruby on Rails 6.1 のデフォルトは Puma. 比較記事; Unicorn vs Puma vs Passengerの比較まとめ | Scout APM Blog

インストール

  • mysql-ruby http://www.tmtm.org/en/mysql/ruby/

    似たようなパッケージが多くある。2021年現在では, 'mysql2' gem パッケージを使えばよい。

    PostgreSQL 用のコネクタは pg パッケージ, SQLite 用は sqlite3 (末尾に3が付く).

  • Ruby on Rails https://rubyonrails.org/

    2021.5 現在の最新は v6.1.3.2. root ユーザになって、gemパッケージをグローバルにインストールする。

SQLite の場合, 次のようにする。

$ su
# gem install rails
# gem install sqlite3

[2021.5] 今は Ruby さえインストールされていれば gem コマンドが入っているので、全部 gem で入れる。

PostgreSQL については, どのLinux ディストリビューションか / 他のUNIXかによって, どのリポジトリから入れるかがかわる。Fedora はディストリビューションのでよいが、Debian, Red Hat/CentOS, SUSE, Ubuntu については PostgreSQL 公式リポジトリを使うのがよい。PostgreSQLのインストール

Fedora リポジトリでは libpq-devel パッケージも入れること。

これらの後, 'pg' gem パッケージを入れる。

Rails のパッケージ集

rails パッケージは、次のサブパッケージから構成される。パッケージが細分化されているし、パッケージの名前も似ていて紛らわしいし、クラス階層も深いので、ドキュメントが探しにくい。

パッケージ 説明
actioncable Structure many real-time application concerns into channels over a single WebSocket connection. Rails5.0 で導入。
actionmailbox Receive and process incoming emails in Rails applications. Rails v6 で導入。
actionmailer Email on Rails. Compose, deliver, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.
actionpack Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server. Rails の中核。リクエストを受け付けてレスポンスを返すまでを担当。
actiontext Edit and display rich text in Rails applications. Rails v6 で導入。
actionview Simple, battle-tested conventions and helpers for building web pages. テンプレートエンジンによる HTML 生成。Rails v5.1から Erubi を利用。
activejob Declare job classes that can be run by a variety of queuing backends. Rails v4.2 で導入。そうだっけ?
activemodel A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, serialization, internationalization, and testing. Active Record と同様の動作を DBMS表オブジェクト以外でもできるようにする。
activerecord Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in. Rails の特徴の一つ、DBMS のテーブルと1:1に対応したモデルクラス。O/Rマッパ。
activestorage Attach cloud and local files in Rails applications. Rails 5.2 で導入.
activesupport A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing. 実用的なクラス群と標準ライブラリの拡張.
railties Rails internals: application bootup, plugins, generators, and rake tasks.
sprockets-rails Sprockets Rails integration.

昔は actionwebservice パッケージで WSDL/SOAP, XML-RPC サポートがあったが、廃れた。

'activesupport', 'activerecord' パッケージは, Ruby on Rails 以外でも使われることがある。汎用的なライブラリになっている。

Model–view–controller, MVC

Ruby on Rails は, MVC パタン (それをWebアプリケィションに当てはめた MVC2) ということになっている。でも独自。

リクエストからレスポンスまでの流れ

左は, アプリケーションサーバは httpサーバに組み込まれた図になっている。

  • [Webブラウザ] -> [httpd] リクエストを投げる。
  • [ディスパッチャ] ここからアプリケィション。リクエストURL などに基づき、どのコントローラが処理するか routing を担当
  • [コントローラ] モデルをまたぐような処理を行い、どのビューでレスポンスするか決定する。ときおり, 別のコントローラに redirect する。
  • [モデル] データベースを扱う
  • [ビュー] Webブラウザに返却するレスポンスを作る。

アプリケィション構成

ディスパッチャはrailsが提供。

役割 パス 技術
モデル app/models/ Active Record
ビュー app/views/ actionview (ERB)
コントローラ app/controllers/ Action Pack

Rails の "モデル" は, RDB の表と1:1対応で、べったり物理的な表とイコールになっている。表をまたぐ処理については, コントローラに書くか、ビジネスロジックを記述するクラスを別に作る。

モデルは, データを更新したときにビューに対してイベントを通知 notify したりもしない。ただの器。Rails 以前の MVC パタンとは様子が異なる。

とはいえ、Rails 後のフレームワークは, Rails と同じ意味の "モデル" を採用することが多く、その点でも Rails は大きな影響を与えた、といえる。

Railsでの開発フロー

  1. ひな形を作る

    rails提供のコマンドを利用

  2. テストを作る

    Rails のコマンドがテストのひな形も作ってくれる

  3. コードを書く -- ひな形を修正

・・・この繰り返し

アプリケイション作成開始

rails new コマンドでアプリケイションの雛形を作る.

$ rails new hello_app

[2021.5] 多くのファイルが自動生成される。長いが、Rails 6.1 で生成されるファイルをひと通り示す。

アプリケィションは app/ 以下に作成する。静的ファイルは public/ 以下.

単体テストは test/ 以下に。

./.git
./.gitattributes
./.gitignore
./.ruby-version
./Gemfile
./README.md
./Rakefile
./app
./app/assets
./app/assets/config
./app/assets/config/manifest.js
./app/assets/images
./app/assets/stylesheets
./app/assets/stylesheets/application.css
./app/channels
./app/channels/application_cable
./app/channels/application_cable/channel.rb
./app/channels/application_cable/connection.rb
./app/controllers
./app/controllers/application_controller.rb
./app/controllers/concerns
./app/helpers
./app/helpers/application_helper.rb
./app/javascript
./app/javascript/channels
./app/javascript/channels/consumer.js
./app/javascript/channels/index.js
./app/javascript/packs
./app/javascript/packs/application.js
./app/jobs
./app/jobs/application_job.rb
./app/mailers
./app/mailers/application_mailer.rb
./app/models
./app/models/application_record.rb
./app/models/concerns
./app/views
./app/views/layouts
./app/views/layouts/application.html.erb
./app/views/layouts/mailer.html.erb
./app/views/layouts/mailer.text.erb
./bin
./bin/rails
./bin/rake
./bin/setup
./bin/spring
./bin/yarn
./config
./config.ru
./config/application.rb
./config/boot.rb
./config/cable.yml
./config/credentials.yml.enc
./config/database.yml
./config/environment.rb
./config/environments
./config/environments/development.rb
./config/environments/production.rb
./config/environments/test.rb
./config/initializers
./config/initializers/application_controller_renderer.rb
./config/initializers/assets.rb
./config/initializers/backtrace_silencers.rb
./config/initializers/content_security_policy.rb
./config/initializers/cookies_serializer.rb
./config/initializers/filter_parameter_logging.rb
./config/initializers/inflections.rb
./config/initializers/mime_types.rb
./config/initializers/permissions_policy.rb
./config/initializers/wrap_parameters.rb
./config/locales
./config/locales/en.yml
./config/master.key
./config/puma.rb
./config/routes.rb
./config/spring.rb
./config/storage.yml
./db
./db/seeds.rb
./lib
./lib/assets
./lib/tasks
./log
./package.json
./public
./public/404.html
./public/422.html
./public/500.html
./public/apple-touch-icon-precomposed.png
./public/apple-touch-icon.png
./public/favicon.ico
./public/robots.txt
./storage
./test
./test/application_system_test_case.rb
./test/channels
./test/channels/application_cable
./test/channels/application_cable/connection_test.rb
./test/controllers
./test/fixtures
./test/fixtures/files
./test/helpers
./test/integration
./test/mailers
./test/models
./test/system
./test/test_helper.rb
./tmp
./tmp/cache
./tmp/cache/assets
./tmp/pids
./tmp/storage
./vendor

Apacheの設定

CGIで動かしてみる.

extra/httpd-vhosts.conf

<VirtualHost *:80>
ServerName rfoto.orange.fruits
DocumentRoot /home/hori/ruby/RFoto/public
UserDir disable
SuexecUserGroup hori hori
ErrorLog /home/hori/ruby/RFoto/log/apache-error_log
CustomLog /home/hori/ruby/RFoto/log/apache-access_log common
</VirtualHost>

単に動かしてみるだけなら, HTTP サーバ, アプリケイションサーバをインストールする必要はない。rackup コマンドで起動できる。

※ Ruby 3.0 の場合, puma, thin, falcon または webrick が入っていないと, rackup に失敗する. そのうえ, 'webrick' gem を入れても動かない。マジか...

→ 'puma', 'thin' か 'passenger' を入れよう。

Gemfile ファイルと database の設定

まずは Gemfileconfig/database.yml ファイルを編集する。

1. Gemfile

Gemfile ファイルを編集し, 利用するパッケージを取捨選択する。とりあえず最低限、これぐらいか。ruby ヴァージョンを変更し, DBMS として SQLite を使う。puma を外す, turbolinks を外す. あとはデフォルトどおり。全文を示す。

Ruby
[RAW]
  1. source 'https://rubygems.org'
  2. git_source(:github) { |repo| "https://github.com/#{repo}.git" }
  3. ruby '>= 2.7.3'
  4. # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
  5. gem 'rails', '~> 6.1.3', '>= 6.1.3.2'
  6. # Use sqlite3 as the database for Active Record
  7. gem 'sqlite3', '~> 1.4'
  8. # Use Puma as the app server
  9. #gem 'puma', '~> 5.0'
  10. # Use SCSS for stylesheets
  11. gem 'sass-rails', '>= 6'
  12. # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
  13. gem 'webpacker', '~> 5.0'
  14. # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
  15. #gem 'turbolinks', '~> 5'
  16. # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
  17. gem 'jbuilder', '~> 2.7'
  18. # Use Redis adapter to run Action Cable in production
  19. # gem 'redis', '~> 4.0'
  20. # Use Active Model has_secure_password
  21. # gem 'bcrypt', '~> 3.1.7'
  22. # Use Active Storage variant
  23. # gem 'image_processing', '~> 1.2'
  24. # Reduces boot times through caching; required in config/boot.rb
  25. gem 'bootsnap', '>= 1.4.4', require: false
  26. group :development, :test do
  27. # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  28. gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  29. end
  30. group :development do
  31. # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  32. gem 'web-console', '>= 4.1.0'
  33. # Display performance information such as SQL time and flame graphs for each request in your browser.
  34. # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
  35. gem 'rack-mini-profiler', '~> 2.0'
  36. gem 'listen', '~> 3.3'
  37. # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  38. gem 'spring'
  39. end
  40. group :test do
  41. # Adds support for Capybara system testing and selenium driver
  42. gem 'capybara', '>= 3.26'
  43. gem 'selenium-webdriver'
  44. # Easy installation and use of web drivers to run system tests with browsers
  45. gem 'webdrivers'
  46. end
  47. # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
  48. gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

不足するパッケージをsystem-wide にインストールするか, すべてのパッケージをプロジェクトローカルにインストールする。

プロジェクトローカルにインストールするのは、プロジェクトごとに全部のヴァージョンを固定したい場合。きちんと維持するのは非常に手間が掛かる。System-wide にインストールするほうがよい。

プロジェクトローカルにするには, bundle config set path コマンドを使う。

$ bundle config set path vendor/bundle
Your application has set path to "vendor/bundle". This will override the global value you are currently setting

いずれにしても, bundle install でインストールする。

Web上の記事でよく bundle install --path vendor/bundle としているものを見かけるが, --path flag は非推奨 (deprecated) になっている。

2. config/database.yml ファイル

DBMS への接続を設定する。デフォルトは SQLite を使うようになっている。

default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test.sqlite3

production:
  <<: *default
  database: db/production.sqlite3

MySQL or MariaDB だと次のようにする。現代は adapter: mysql2. ホストが "localhost" または空の場合, socket パラメタが必須。

development:
  adapter: mysql2
  host: localhost
  username: MySQLユーザ名
  password: パスワード
  database: データベース名
  encoding: utf8 ・・・これで文字コードを指定
  socket: /tmp/mysql.sock

アプリケーションサーバを起動する。

$ passenger start
=============== Phusion Passenger(R) Standalone web server started ===============
PID file: /home/hori/src_local/hello_app/tmp/pids/passenger.3000.pid
Log file: /home/hori/src_local/hello_app/log/passenger.3000.log
Environment: development
Accessible via: http://0.0.0.0:3000/

表示された! Yay!