React + Rails API モードで基本的な CRUD アプリを作ってみた (バックエンド編)
はじめに
世は大 SPA 時代!!
「そろそろフロントもやっておくか」ということでReact の公式チュートリアルをやりました。
が、実際のアプリケーションではバックエンドとAPIレベルで通信することは必須。
簡単な CRUD 機能を持つバックエンドをRailsの API モードを使って実装し、はじめての SPA に挑戦してみることにしました。
初心者なので至らない部分も沢山あると思いますが、「Rails API + React フロントエンド」という実装についてイメージできるようになっていると思います。
今回は最小限の構成(モデル1つ、コントローラ1つ)ですが、基礎を抑えておけばスケールすることは十分可能だと思います。
それではやっていきましょう🙋♂️
No | Title | |
---|---|---|
1 | バックエンド編 | ← 今ここ |
2 | フロントエンド編 その1 | |
3 | フロントエンド編 その2 | |
4 | その他考察編 |
作ったアプリ
ポストを投稿できるだけのシンプルなアプリです。
ポストに対して CRUD 処理を実装していきます。
環境、リポジトリ
Name | Version |
---|---|
node.js | 12.19.0 |
React | 16.13.1 |
Ruby | 2.6.6 |
Rails | 6.0.3.4 |
Docker for Mac | 2.4.0.0 |
Name | URL |
---|---|
フロントエンド | https://github.com/tatsuro-m/react_rails_api_frontend |
バックエンド | https://github.com/tatsuro-m/react_rails_api_backend |
アプリの構成はどのようにするか
ネット上で記事を確認していると、 rails new
したアプリルート直下に frontend
などのディレクトリを作ってその下に create-react-app
でReact 部分を作るというのを良く見ました。
しかし個人的にはこのディレクトリ構成はしっくりきません。
「完全に別々のアプリなんだ」ということをハッキリするためにプロジェクト、リポジトリごと別々に分けました。
結果、今のところこれで良かったと思っています。
Name | URL |
---|---|
フロントエンド | https://github.com/tatsuro-m/react_rails_api_frontend |
バックエンド | https://github.com/tatsuro-m/react_rails_api_backend |
こうした方が別々のライフサイクルでアプリを動かすことができる気がします。
今回はそこまで関係ありませんが、別のプロジェクトとしておくと、
- コンテナ基盤で別々のインフラスケーリングがやりやすい
- コミットがフロントとバックエンドで混ざらない
- 動作の切り分けがより直感的
- CI/CD パイプラインも別々にしやすい
などのメリットがありそうです。
この辺はお好みですね😁
環境構築
- バックエンド → Docker を使ってサクッと立ち上げます
- フロントエンド → Mac にインストールした node.js を使います(Docker 使っても良いのですが、
node_modules
配下が重いですし、こっちの方が楽でした)
詳しくは、非常に簡単ですが README に手順が書いてあるので参考にしてください!
基本的に、
- api モードで
rails new
する -
create-react-app
でReact アプリ作成
ぐらいです。。。
バックエンド
Docker で環境が立ち上がったらバックエンドはサクッと片付けてしまいましょう。
コントローラー
rails g controller posts
します。
中身は割とお作法通りの、
class PostsController < ApplicationController
before_action :set_post, only: %i[show destroy update]
def index
posts = Post.all.order(:id)
render json: posts
end
def show
render json: @post
end
def create
post = Post.new(post_params)
if post.save
render json: post
else
render json: post.errors
end
end
def update
if @post.update(post_params)
render json: @post
else
render json: @post.errors
end
end
def destroy
if @post.destroy
render json: @post
else
render json: @post.errors
end
end
private
def set_post
@post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
end
となっております!!
注意点としては、
- 基本的に実装するアクションは「フロントにデータを返す」アクションだけ
- API レベルで通信するので、いつものように view をレンダリングするのではなく、
render json: {data}
で返す。
ぐらいでしょうか。
必要なアクションは作りたい形によって若干変わるのですが、ビューの部分は完全にReact に任せるのが前提なので、 new
や edit
アクションは不要です。データを返すわけでは無いからです。
show
も今回は入っていますが、不要な場合もあると思います。
ストロングパラメータはいつも通り使うようにしましょう😁
ルーティングの設定をお忘れなく!
モデル
rails g model Post
します。
今回はシンプルに、
create_table "posts", force: :cascade do |t|
t.string "title", null: false
t.text "content", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
こんなスキーマでやってみました。
title
と content
があるだけのモデルです。
ポストを投稿できるアプリですね。
seed を流しておくと動作確認が楽です。
rails db:seed
curl で確認しておきましょうか。
curl -X GET http://localhost:3001/posts | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3620 0 3620 0 0 60333 0 --:--:-- --:--:-- --:--:-- 60333
[
{
"id": 59,
"title": "サンプル0",
"content": "これはseedで作成したものです。",
"created_at": "2020-10-18T04:34:49.594Z",
"updated_at": "2020-10-18T04:34:49.594Z"
},
{
"id": 60,
"title": "サンプル1",
"content": "これはseedで作成したものです。",
"created_at": "2020-10-18T04:34:49.608Z",
"updated_at": "2020-10-18T04:34:49.608Z"
},
json でデータが返ってくれば成功です!!
これでバックエンドは基本的に終わりなのですが、1点注意を。
API モードのRailsが異なるオリジン(この場合はフロントのReact アプリ)からアクセスを受けるためには明示的にアクセスを許可する必要があります。
gem 'rack-cors'
をコメントインして(new した時点で Gemfile にコメントアウトされて入っています)、 bundle install
。
設定を追記しておきましょう。
~~~
config.middleware.insert_before 0, Rack::Cors do
allow do
origins ENV["FRONTEND_ORIGIN"]
resource "*",
headers: :any,
methods: [:get, :post, :patch, :delete, :options, :head]
end
end
これで再起動すればフロントからのアクセスができるはずです。
ちなみに、環境変数 FRONTEND_ORIGIN
は、docker-compose.yml
に記載されています。
FRONTEND_ORIGIN: http://localhost:3000
オリジンは環境によって分けることが多いと思いますので、環境変数を使っています。
バックエンド編はここまで!
次回はいよいよReact アプリを構成していきます🙌
PS. やっぱりRailsって開発自体はすごく早いですよね🧐
次回もお楽しみに!!
Discussion