[Rails] 単一ファイルのRailsアプリケーションを作ってみた

# はじめに
https://techracho.bpsinc.jp/hachi8833/2024_06_20/142528

上記の記事で、気になる箇所がありました。

**1ファイルで動くRailsアプリケーションを作った**

これを見た時の自分は、「え？そんなことできるの？」と思いました。

https://greg.molnar.io/blog/a-single-file-rails-application/

上記記事の記載があったので、参考にして自分も作ってみました。
その内容をアウトプットいたします。

# 実装
## 環境
- Ruby：3.2.2

お好きなディレクトリで、`app.ru`を作成します。

```rb:app.ru
# frozen_string_literal: true
require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'rails', '7.0.4'
  gem 'sqlite3', '~> 1.4'
  gem 'puma'
end

require 'rails/all'
database = 'development.sqlite3'

ENV['DATABASE_URL'] = "sqlite3:#{database}"
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: database)
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord.legacy_connection_handling = false
ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
  end

  create_table :comments, force: true do |t|
    t.integer :post_id
  end
end

class App < Rails::Application
  config.root = __dir__
  config.consider_all_requests_local = true
  config.secret_key_base = 'i_am_a_secret'
  config.active_storage.service_configurations = { 'local' => { 'service' => 'Disk', 'root' => './storage' } }

  routes.append do
    root to: 'welcome#index'
  end
end

class WelcomeController < ActionController::Base
  def index
    render inline: 'Hi!'
  end
end

App.initialize!

run App
```

## 解説
### `sqlite3`のバージョンは指定しよう
指定をしないと、以下のようなエラーが出ます。

```sh
Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.4), already activated sqlite3-2.0.2-x86_64-darwin. Make sure all dependencies are added to Gemfile. (LoadError)
```

エラーに記載通りではありますが、`~> 1.4`を指定して、エラーを解消しました。

### gem `puma`は入れよう
Webサーバーハンドラーがないと、以下のエラーが出ます。

```sh
Couldn't find handler for: puma, thin, falcon, webrick. (LoadError)
```

自分は、馴染みのあった`puma`を導入しました。

### `legacy_connection_handling = false`で設定しよう
上記の設定がないと、以下の警告文が出ます。

```sh
DEPRECATION WARNING: Using legacy connection handling is deprecated. Please set
`legacy_connection_handling` to `false` in your application.
```

なので、以下のように記載すると、警告は解消されます。

```rb
ActiveRecord.legacy_connection_handling = false
```

## 実行
上記のファイルが用意できたら、以下のコマンドで実行します。

```sh
rackup app.ru
```

そうすると、ログは以下のような感じになります。

```sh
Fetching gem metadata from https://rubygems.org/...........
Resolving dependencies...
Using rake 13.2.1
Using concurrent-ruby 1.3.3
Using minitest 5.24.0
Using builder 3.3.0
Using erubi 1.13.0
Using rack 2.2.9
Using nio4r 2.7.3
Using racc 1.8.0
Using crass 1.0.6
Using websocket-extensions 0.1.5
Using timeout 0.4.1
Using sqlite3 1.7.3 (x86_64-darwin)
Using mini_mime 1.1.5
Using date 3.3.4
Using method_source 1.1.0
Using thor 1.3.1
Using bundler 2.4.10
Using zeitwerk 2.6.16
Using i18n 1.14.5
Using marcel 1.0.4
Using tzinfo 2.0.6
Using rack-test 2.1.0
Using puma 6.4.2
Using nokogiri 1.16.6 (x86_64-darwin)
Using activesupport 7.0.4
Using websocket-driver 0.7.6
Using net-protocol 0.2.2
Using rails-dom-testing 2.2.0
Using net-imap 0.4.14
Using globalid 1.2.1
Using activemodel 7.0.4
Using net-pop 0.1.2
Using activerecord 7.0.4
Using net-smtp 0.5.0
Using loofah 2.22.0
Using activejob 7.0.4
Using rails-html-sanitizer 1.6.0
Using mail 2.8.1
Using actionview 7.0.4
Using actionpack 7.0.4
Using railties 7.0.4
Using actioncable 7.0.4
Using activestorage 7.0.4
Using actionmailer 7.0.4
Using actionmailbox 7.0.4
Using actiontext 7.0.4
Using rails 7.0.4
-- create_table(:posts, {:force=>true})
D, [2024-06-24T22:43:57.047342 #79113] DEBUG -- :    (1.4ms)  DROP TABLE IF EXISTS "posts"
D, [2024-06-24T22:43:57.048653 #79113] DEBUG -- :    (0.9ms)  CREATE TABLE "posts" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL)
   -> 0.0083s
-- create_table(:comments, {:force=>true})
D, [2024-06-24T22:43:57.049449 #79113] DEBUG -- :    (0.6ms)  DROP TABLE IF EXISTS "comments"
D, [2024-06-24T22:43:57.050090 #79113] DEBUG -- :    (0.6ms)  CREATE TABLE "comments" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "post_id" integer)
   -> 0.0014s
D, [2024-06-24T22:43:57.078484 #79113] DEBUG -- :   ActiveRecord::InternalMetadata Load (2.7ms)  SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ?  [["key", "environment"], ["LIMIT", 1]]
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:

  * development - set it to false
  * test - set it to false (unless you use a tool that preloads your test environment)
  * production - set it to true

Puma starting in single mode...
* Puma version: 6.4.2 (ruby 3.2.2-p53) ("The Eagle of Durango")
*  Min threads: 0
*  Max threads: 5
*  Environment: development
*          PID: 79113
* Listening on http://127.0.0.1:9292
* Listening on http://[::1]:9292
* Listening on http://127.0.2.2:9292
* Listening on http://127.0.2.3:9292
Use Ctrl-C to stop
```

上記のようになっていたら、`http://127.0.0.1:9292`で開いて、画面が表示されていたら、実行は成功かと思います。

![Group 1 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2849898/11481712-730b-6e51-b1f7-dfad7f9c94eb.png)

# まとめ
スキーマもかけて、ルーティングからビューの表示までを1ファイルでまとめることができました。
具体的な使い道はまだわかっていないですが、普段とは違う使い方を知ることができて、良い勉強になりました。

最後までご覧いただき、ありがとうございました。


# 参考文献
https://techracho.bpsinc.jp/hachi8833/2024_06_20/142528

https://greg.molnar.io/blog/a-single-file-rails-application/