ruby on rails admin/frontend 常用架构

rails 有一个 admin/frontned 2个大模块,admin 只要提供api即可(我会用其它技术开发 admin 后台); frontend 会使用 erb 生成 html

你描述的 Rails 项目结构非常清晰:一个 Rails 应用,包含两个大模块:

  • admin:仅提供 API 接口,供外部管理后台(可能用 Vue、React、Next.js 等)调用。
  • frontend:使用 ERB 模板渲染 HTML 页面,面向普通用户。

下面我为你详细说明如何在 Rails 中实现这种架构设计,并给出最佳实践建议。


✅ 一、整体架构设计

app/
├── controllers/
│   ├── api/                 # API 控制器(admin 使用)
│   │   └── v1/
│   │       ├── users_controller.rb
│   │       └── ...
│   ├── frontend/            # 前台控制器(ERB 渲染)
│   │   ├── pages_controller.rb
│   │   └── ...
│   └── application_controller.rb
├── views/
│   ├── frontend/            # ERB 模板
│   │   ├── pages/
│   │   │   └── home.html.erb
│   │   └── layouts/
│   │       └── application.html.erb
│   └── api/                 # 无视图(API 不需要)
└── helpers/
    └── frontend/            # 前台辅助方法

config/routes.rb                            # 路由分离

✅ 二、路由设计(关键)

config/routes.rb 中分离两个模块:

Rails.application.routes.draw do
  # 前台:HTML 页面,使用 ERB
  scope module: 'frontend' do
    root 'pages#home'
    get '/about', to: 'pages#about'
    # 其它页面...
  end

  # 后台 API:JSON 接口,版本化
  namespace :api do
    namespace :v1 do
      resources :users, only: [:index, :show, :create, :update, :destroy]
      post '/login', to: 'sessions#create'
      # 其它 API...
    end
  end
end

访问示例:

  • 前台页面:GET /frontend/pages#home
  • API 接口:GET /api/v1/usersapi/v1/users#index

✅ 三、控制器分离

1. 前台控制器(ERB 渲染)

# app/controllers/frontend/pages_controller.rb
class Frontend::PagesController < ApplicationController
  def home
    @title = "首页"
  end

  def about
    @title = "关于我们"
  end
end

2. API 控制器(仅返回 JSON)

# app/controllers/api/v1/users_controller.rb
module Api
  module V1
    class UsersController < ApplicationController
      before_action :authenticate_admin!, except: [:index]  # 可选鉴权

      def index
        users = User.all
        render json: { data: users }, status: :ok
      end

      def show
        user = User.find(params[:id])
        render json: { data: user }
      end

      def create
        user = User.new(user_params)
        if user.save
          render json: { data: user, message: "创建成功" }, status: :created
        else
          render json: { errors: user.errors }, status: :unprocessable_entity
        end
      end

      # ... update, destroy
      private

      def user_params
        params.require(:user).permit(:name, :email)
      end
    end
  end
end

✅ 四、基础控制器设计

1. Application Controller(通用)

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  # 可添加通用 helper_method、current_user 等
end

2. API 基类控制器(可选)

# app/controllers/api/v1/base_controller.rb
module Api
  module V1
    class BaseController < ApplicationController
      skip_before_action :verify_authenticity_token  # API 不需要 CSRF
      respond_to :json

      rescue_from ActiveRecord::RecordNotFound do |e|
        render json: { error: '记录未找到' }, status: :not_found
      end

      private

      def authenticate_admin!
        # 示例:使用 Token 鉴权
        # header: Authorization: Bearer xxx
        token = request.headers['Authorization']&.split(' ')&.last
        unless token && AdminToken.valid?(token)
          render json: { error: '未授权' }, status: :unauthorized
        end
      end
    end
  end
end

然后让所有 API 控制器继承它:

class Api::V1::UsersController < Api::V1::BaseController
  # ...
end

✅ 五、视图(仅 frontend 使用 ERB)

<!-- app/views/frontend/pages/home.html.erb -->
<% content_for :title, @title %>

<h1>欢迎来到首页</h1>
<p>这是使用 ERB 渲染的页面。</p>

布局文件:

<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
  <title><%= yield :title %></title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>
  <%= stylesheet_link_tag 'application', 'data-turbo-track': 'reload' %>
</head>
<body>
  <%= yield %>
</body>
</html>

✅ 六、静态资源与前端分离建议

  • frontend:继续使用 Rails 的 Asset Pipeline(Sprockets)或导入 Webpacker / Importmap。
  • admin:完全外部开发(如用 React/Vue),部署为独立站点,通过 CORS 调用 Rails 的 /api/v1/* 接口。

配置 CORS(重要!)

使用 rack-cors gem:

# Gemfile
gem 'rack-cors'

# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://admin.example.com'  # 你的 admin 域名

    resource '/api/v1/*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options],
      credentials: true
  end
end

✅ 七、可选:命名空间优化

你也可以使用更清晰的命名空间:

  • Frontend::PagesController
  • Api::V1::UsersController

并通过 scopenamespace 控制路由。


✅ 八、总结:最佳实践

| 项目 | 建议 |
|------|------|
| API 设计 | 版本化(/api/v1/...) |
| 认证 | 使用 JWT / Token / Devise Token Auth |
| 前台 | ERB + Rails 内置视图 |
| 后台 | 外部 SPA,调用 API |
| 鉴权 | before_action :authenticate_admin! |
| 错误处理 | rescue_from 统一返回 JSON |
| CORS | 配置 rack-cors 允许 admin 域名 |
| 日志 | API 请求建议记录日志 |


✅ 九、后续扩展建议

  • 使用 ActiveModel::SerializerJbuilder 格式化 JSON 输出。
  • 使用 Devise 管理后台用户(可配合 devise_token_auth)。
  • 前台用户登录也可走 API(如果未来要做 SPA)。

如果你希望我生成一个完整的示例项目结构或代码模板,也可以告诉我,我可以帮你生成脚手架代码。