はじめに
この記事では、React Admin と Rails API を使って、シンプルな管理画面を構築する方法を紹介します。最終的には投稿(Post)とユーザー(User)を管理できる画面を作ります。
前半はほぼ公式チュートリアルに従って行い、後半は Rails API を使って自分の作ったデータへ干渉できるようにします。
最終的な完成イメージは次の通りです。
※ 本記事では「React Admin を使った管理画面の構築」にフォーカスして進めていきます。
Ruby on Rails 環境(Ruby や Bundler、Rails 本体など)のセットアップについては省略していますので、必要に応じてあらかじめご準備いただければと思います。
React Admin 環境構築
まずは、React Admin の開発環境をセットアップしていきます。以下のコマンドをターミナルで実行してください。
$ npm init react-admin test-admin
$ cd test-admin
$ npm install ra-data-json-server
$ npm run dev
http://localhost:5173 にアクセスして次のような画面になったら正しく動いています。
次にデータ取得や更新のために dataProvider を設定する必要があります。dataProvider.ts
を作成してsrc/
に追加します。
import jsonServerProvider from 'ra-data-json-server';
const dataProvider = jsonServerProvider('https://jsonplaceholder.typicode.com');
export default dataProvider;
この jsonServerProvider
は、React Admin が用意している公式の REST API クライアントで、指定した URL に対して GET、POST、PUT などのリクエストを自動的に発行してくれます。
ここでは、モックデータ API として有名な JSONPlaceholder を使用しています。
このサービスでは、投稿データ(/posts
)やユーザー情報(/users
)など、管理画面に必要なサンプルデータが RESTful API 形式で提供されています。
試しに、https://jsonplaceholder.typicode.com/posts にアクセスすると次のようなデータが得られると思います。
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
...
{
"userId": 10,
"id": 99,
"title": "temporibus sit alias delectus eligendi possimus magni",
"body": "quo deleniti praesentium dicta non quod\naut est molestias\nmolestias et officia quis nihil\nitaque dolorem quia"
},
{
"userId": 10,
"id": 100,
"title": "at nam consequatur ea labore ea harum",
"body": "cupiditate quo est a modi nesciunt soluta\nipsa voluptas error itaque dicta in\nautem qui minus magnam et distinctio eum\naccusamus ratione error aut"
}
]
このデータを次のステップで綺麗に表示していきます。
投稿管理画面の作成
一覧画面の作成
まずは投稿(Post)の一覧を表示するために、次のようにフォルダ/ファイルを追加します。
src/
に pages
フォルダ、そしてその下に posts
フォルダを作成し、そこに PostList.tsx
を追加します。
React Admin の List
コンポーネントと Datagrid
を使って、投稿の ID、タイトル、本文、ユーザーを一覧表示できるようにします。
import { List, Datagrid, TextField, ReferenceField, EditButton } from "react-admin";
const PostList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
<ReferenceField source="userId" reference="users" />
<EditButton />
</Datagrid>
</List>
);
export default PostList;
次に、App.tsx
を編集してこの画面をルーティングに追加します。
import { Admin, Resource } from "react-admin";
import dataProvider from './dataProvider';
import PostList from './pages/posts/PostList';
export const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts"
list={PostList}
/>
</Admin>
);
ここまで実装すると、投稿の一覧が表形式で表示されるようになります。
詳細・編集・新規作成ページの追加
同様に次のファイルも作成して、詳細ページ、編集ページ、新規作成ページも作ります。
import { Show, SimpleShowLayout, TextField, ReferenceField } from "react-admin";
const PostShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
<ReferenceField source="userId" reference="users" />
</SimpleShowLayout>
</Show>
);
export default PostShow;
import { Edit, SimpleForm, TextInput, ReferenceInput } from "react-admin";
const PostEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="title" />
<TextInput source="body" />
<ReferenceInput source="userId" reference="users" />
</SimpleForm>
</Edit>
);
export default PostEdit;
import { Create, SimpleForm, TextInput, ReferenceInput } from "react-admin";
const PostCreate = () => (
<Create>
<SimpleForm>
<TextInput source="title" />
<TextInput source="body" multiline rows={5} />
<ReferenceInput source="userId" reference="users" />
</SimpleForm>
</Create>
);
export default PostCreate;
App.tsx
に詳細・編集・作成ページを追加してルーティングを有効にします。
import { Admin, Resource } from "react-admin";
import dataProvider from './dataProvider';
import PostList from './pages/posts/PostList';
+ import PostShow from './pages/posts/PostShow';
+ import PostEdit from './pages/posts/PostEdit';
+ import PostCreate from './pages/posts/PostCreate';
export const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts"
list={PostList}
+ show={PostShow}
+ edit={PostEdit}
+ create={PostCreate}
/>
</Admin>
);
ここまでの実装が完了すると、一覧から投稿の詳細を確認したり、編集画面・作成画面へ遷移できるようになります。
なお、今は外部のモック API(JSONPlaceholder)を使用しているため、編集や新規作成を行っても実際にはサーバー側に保存されません。そのため、扱えるのは一覧と詳細のみとなります。
Rails API の設定
このステップでは、React Admin のフロントエンドと連携するための Rails API サーバーを構築していきます。まずはデータベース設計として Post
モデルと User
モデルを用意し、それらのリレーション設定、初期データの投入までを行います。
モデル作成
まずは、投稿情報を管理する Post
モデルと、それに紐づくユーザー情報を管理する User
モデルを作成します。
$ rails g model Post
$ rails g model User
それぞれのマイグレーションファイルを編集して、必要なカラムを追加します。
class CreatePosts < ActiveRecord::Migration[7.1]
def change
create_table :posts do |t|
+ t.string :title
+ t.text :body
+ t.integer :user_id
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration[7.1]
def change
create_table :users do |t|
+ t.string :name
+ t.string :email
t.timestamps
end
end
end
カラムの追加が完了したら、マイグレーションを実行してテーブルを作成します。
$ rails db:migrate
加えて、User
は複数の Post
を持つ(1:N
)、という関係性をモデルに定義します。
これで、ユーザーと投稿がリレーションで繋がり、Rails 側での関連付けができるようになります。
class Post < ApplicationRecord
belongs_to :user
end
class User < ApplicationRecord
has_many :posts, dependent: :destroy
end
また、今回は一覧画面を作るので初期データをあらかじめ作っておきます。
User.create!(name: "Alice", email: "alice@example.com")
User.create!(name: "Bob", email: "bob@example.com")
User.create!(name: "Charlie", email: "charlie@example.com")
User.all.each do |user|
4.times do |n|
user.posts.create!(
title: "テストタイトル#{n + 1}",
body: "テスト本文#{n + 1}"
)
end
end
$ rails db:seed
これで初期データの投入が完了しました。
この段階で、React Admin から扱うための基本的なデータ構造が整いました。次はこれらのデータを外部へ公開するために、API エンドポイントの実装に進んでいきます。
コントローラー作成
ここからは、React Admin 側と通信するための Rails 側の API コントローラーを作成していきます。
前ステップで作成したモデルに対して、一覧取得・詳細取得・作成・更新・削除といった典型的な REST 操作を提供するエンドポイントを整備します。
$ rails g controller api/v1/posts
$ rails g controller api/v1/users
このコマンドで、それぞれのエンドポイントに対応するコントローラーファイルとルーティングが生成されます。
続いて、Api::V1::PostsController
に RESTful なアクションを実装していきます。
class Api::V1::PostsController < ApplicationController
def index
start_params = params[:_start].present? ? params[:_start].to_i : 0
end_params = params[:_end].present? ? params[:_end].to_i : 10
limit = end_params - start_params
posts = Post.offset(start_params).limit(limit)
response.set_header('X-Total-Count', Post.all.count)
render json: posts
end
def show
post = Post.find(params[:id])
render json: post
end
def create
post_new = Post.new(post_params)
if post_new.save
render json: post_new
else
render json: { status: 'error', errors: post_new.errors.full_messages }
end
end
def update
post = Post.find(params[:id])
if post.update(post_params)
render json: post
else
render json: { status: 'error', errors: post.errors.full_messages }
end
end
def destroy
post = Post.find(params[:id])
post.destroy
render json: post
end
private
def post_params
params.require(:post).permit(:title, :body, :user_id)
end
end
同様に、ユーザー一覧などを取得できる Api::V1::UsersController
を実装します。
class Api::V1::UsersController < ApplicationController
def index
start_params = params[:_start].present? ? params[:_start].to_i : 0
end_params = params[:_end].present? ? params[:_end].to_i : 10
limit = end_params - start_params
users = User.offset(start_params).limit(limit)
response.set_header('X-Total-Count', User.all.count)
render json: users
end
def show
user = User.find(params[:id])
render json: user
end
def create
user_new = User.new(user_params)
if user_new.save
render json: user_new
else
render json: { status: 'error', errors: user_new.errors.full_messages }
end
end
def update
user = User.find(params[:id])
if user.update(user_params)
render json: user
else
render json: { status: 'error', errors: user.errors.full_messages }
end
end
def destroy
user = User.find(params[:id])
user.destroy
render json: user
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
最後に、ルーティングファイルを編集して API を有効にします。
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :posts, except: %i[new edit]
resources :users, except: %i[new edit]
end
end
end
これで、React Admin 側から http://localhost:3000/api/v1/posts や http://localhost:3000/api/v1/users に対してリクエストを送ることで、Rails 側のデータと連携できるようになりました。
その他設定
フロントエンドと Rails API を連携させる際、サーバー側の設定もいくつか必要になります。そのままでは CSRF や CORS の制約に引っかかってしまうため、以下のように設定を加えていきます。
まずは Rails を API 専用モードに設定します。これにより、不要なビューやアセット、CSRF 保護などが無効化され、API サーバーとしてシンプルになります。
module App
class Application < Rails::Application
...
config.api_only = true
end
end
次に、CORS(オリジン間リソース共有)を許可する設定を行います。Rails では rack-cors
というミドルウェアを使うのが一般的です。
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:5173" # React Admin の開発サーバーURL
resource "*",
headers: :any,
expose: ['X-Total-Count'],
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
もし config/initializers/cors.rb
が存在しない場合は、Gemfile
に以下を追記してから bundle install
を実行してください。
+ gem "rack-cors"
$ bundle install
これでフロントエンドと接続する準備が完了しました。
次のステップでは、React Admin 側の dataProvider
をローカルの Rails API に切り替え、実際に CRUD 処理を動かしてみます。
投稿管理画面の修正
ここからは、フロントエンド(React Admin)を Rails のローカル API サーバーに接続するように切り替えていきます。
前ステップまでは https://jsonplaceholder.typicode.com を使っていましたが、ここからは自分で立てた Rails API を使って、投稿やユーザーの追加・削除などができるようになります。
import jsonServerProvider from 'ra-data-json-server';
const dataProvider = jsonServerProvider('http://localhost:3000/api/v1');
export default dataProvider;
また、Rails のデフォルトでは外部キー名はスネークケース(user_id
)となっているため、React Admin 側のフィールド指定もそれに合わせる必要があります。
import { List, Datagrid, TextField, ReferenceField, EditButton } from "react-admin";
const PostList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="title" />
<TextField source="body" />
+ <ReferenceField source="user_id" reference="users" />
<EditButton />
</Datagrid>
</List>
);
export default PostList;
この修正は一覧表示に限らず、詳細表示(PostShow.tsx
)、編集(PostEdit.tsx
)、新規作成(PostCreate.tsx
)など、該当フィールドを使用している全ての画面に適用してください。
rails db:seed
で投入したテストデータが、上のように一覧画面で表示されていれば成功です。
ユーザー管理画面の作成
加えて User
の管理画面も作ってみましょう。
import { List, Datagrid, TextField, EditButton } from "react-admin";
const UserList = () => (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="name" />
<TextField source="email" />
<EditButton />
</Datagrid>
</List>
);
export default UserList;
import { Show, SimpleShowLayout, TextField } from "react-admin";
const UserShow = () => (
<Show>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="name" />
<TextField source="email" />
</SimpleShowLayout>
</Show>
);
export default UserShow;
import { Edit, SimpleForm, TextInput } from "react-admin";
const UserEdit = () => (
<Edit>
<SimpleForm>
<TextInput source="name" />
<TextInput source="email" />
</SimpleForm>
</Edit>
);
export default UserEdit;
import { Create, SimpleForm, TextInput } from "react-admin";
const UserCreate = () => (
<Create>
<SimpleForm>
<TextInput source="name" />
<TextInput source="email" />
</SimpleForm>
</Create>
);
export default UserCreate;
最後に、App.tsx
にユーザーリソースを追加して表示されるようにします。
import { Admin, Resource } from "react-admin";
import dataProvider from './dataProvider';
import PostList from './pages/posts/PostList';
import PostShow from './pages/posts/PostShow';
import PostEdit from './pages/posts/PostEdit';
import PostCreate from './pages/posts/PostCreate';
+ import UserList from './pages/users/UserList';
+ import UserShow from './pages/users/UserShow';
+ import UserEdit from './pages/users/UserEdit';
+ import UserCreate from './pages/users/UserCreate';
export const App = () => (
<Admin dataProvider={dataProvider}>
<Resource name="posts"
list={PostList}
show={PostShow}
edit={PostEdit}
create={PostCreate}
/>
+ <Resource name="users"
+ list={UserList}
+ show={UserShow}
+ edit={UserEdit}
+ create={UserCreate}
+ />
</Admin>
);
表示を確認して、ユーザー一覧や詳細、編集・作成ページが問題なく表示されていれば完了です。
これで、投稿とユーザーの CRUD 管理ができるシンプルな管理画面がひと通り完成しました。
おわりに
今回は React Admin と Rails API による実用的な管理画面作成を行いました。
-
外部サービス(
jsonplaceholder
)からスタート -
ローカル API に切り替え
-
投稿とユーザーの一覧 / 詳細 / 編集 / 作成まで対応
という一連の流れを通して、React Admin の基本的な使い方と、Rails API の連携方法が理解できたと思います。
ぜひ自分のプロジェクトにも活用してみてください!
参考サイト