Rails项目结构 #
一、项目根目录 #
1.1 目录概览 #
text
myapp/
├── app/ # 应用核心代码
├── bin/ # 可执行脚本
├── config/ # 配置文件
├── db/ # 数据库相关
├── lib/ # 扩展库
├── log/ # 日志文件
├── public/ # 公共静态文件
├── storage/ # Active Storage文件
├── test/ # 测试文件
├── tmp/ # 临时文件
├── vendor/ # 第三方代码
├── .gitignore # Git忽略文件
├── Gemfile # Gem依赖声明
├── Gemfile.lock # Gem版本锁定
├── config.ru # Rack配置
├── Rakefile # Rake任务
└── README.md # 项目说明
1.2 根目录文件 #
| 文件 | 说明 |
|---|---|
| Gemfile | 定义项目依赖的Gem |
| Gemfile.lock | 锁定Gem的具体版本 |
| config.ru | Rack应用启动配置 |
| Rakefile | 定义Rake任务 |
| README.md | 项目说明文档 |
二、app目录 #
2.1 app目录结构 #
text
app/
├── controllers/ # 控制器
│ ├── application_controller.rb
│ └── concerns/
├── models/ # 模型
│ ├── application_record.rb
│ └── concerns/
├── views/ # 视图
│ ├── layouts/
│ └── [controller_name]/
├── helpers/ # 辅助方法
├── javascript/ # JavaScript代码
├── assets/ # 静态资源
│ ├── stylesheets/
│ ├── images/
│ └── builds/
├── mailers/ # 邮件发送器
├── jobs/ # 后台任务
├── channels/ # WebSocket频道
└── uploaders/ # 文件上传器
2.2 controllers目录 #
text
app/controllers/
├── application_controller.rb # 基础控制器
├── concerns/ # 共享模块
│ └── authentication.rb
├── users_controller.rb # 用户控制器
├── articles_controller.rb # 文章控制器
└── admin/ # 命名空间
└── dashboard_controller.rb
application_controller.rb:
ruby
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# 所有控制器的基类
# 可以在这里定义共享的方法和过滤器
before_action :require_login
helper_method :current_user
private
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def require_login
redirect_to login_path unless current_user
end
end
控制器命名规范:
| 文件名 | 类名 | 说明 |
|---|---|---|
| users_controller.rb | UsersController | 复数形式 |
| articles_controller.rb | ArticlesController | 复数形式 |
| admin/users_controller.rb | Admin::UsersController | 命名空间 |
2.3 models目录 #
text
app/models/
├── application_record.rb # 基础模型
├── concerns/ # 共享模块
│ └── searchable.rb
├── user.rb # 用户模型
├── article.rb # 文章模型
└── comment.rb # 评论模型
application_record.rb:
ruby
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
# 所有模型的基类
# 可以在这里定义共享的方法
end
模型命名规范:
| 文件名 | 类名 | 表名 |
|---|---|---|
| user.rb | User | users |
| article.rb | Article | articles |
| order_item.rb | OrderItem | order_items |
concerns示例:
ruby
# app/models/concerns/searchable.rb
module Searchable
extend ActiveSupport::Concern
included do
scope :search, ->(query) { where("name LIKE ?", "%#{query}%") }
end
end
# app/models/article.rb
class Article < ApplicationRecord
include Searchable
end
2.4 views目录 #
text
app/views/
├── layouts/ # 布局模板
│ ├── application.html.erb
│ ├── mailer.html.erb
│ └── admin.html.erb
├── articles/ # 文章视图
│ ├── index.html.erb
│ ├── show.html.erb
│ ├── new.html.erb
│ ├── edit.html.erb
│ └── _form.html.erb # 部分视图(以_开头)
├── shared/ # 共享视图
│ ├── _header.html.erb
│ ├── _footer.html.erb
│ └── _nav.html.erb
└── devise/ # Devise视图(如使用)
布局文件:
erb
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>MyApp</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body>
<%= render 'shared/header' %>
<main>
<%= yield %> <!-- 内容插入点 -->
</main>
<%= render 'shared/footer' %>
</body>
</html>
命名规范:
| 文件名 | 说明 |
|---|---|
| index.html.erb | 列表页面 |
| show.html.erb | 详情页面 |
| new.html.erb | 新建页面 |
| edit.html.erb | 编辑页面 |
| _form.html.erb | 部分视图(表单) |
| _article.html.erb | 部分视图(文章) |
2.5 helpers目录 #
text
app/helpers/
├── application_helper.rb # 全局辅助方法
├── articles_helper.rb # 文章辅助方法
└── users_helper.rb # 用户辅助方法
辅助方法示例:
ruby
# app/helpers/application_helper.rb
module ApplicationHelper
def page_title(title)
title.present? ? "#{title} | MyApp" : "MyApp"
end
def format_date(date)
date.strftime('%Y年%m月%d日')
end
def markdown(text)
renderer = Redcarpet::Render::HTML.new
markdown = Redcarpet::Markdown.new(renderer)
markdown.render(text).html_safe
end
end
# app/helpers/articles_helper.rb
module ArticlesHelper
def article_status_badge(article)
case article.status
when 'published'
content_tag(:span, '已发布', class: 'badge bg-success')
when 'draft'
content_tag(:span, '草稿', class: 'badge bg-secondary')
end
end
end
2.6 javascript目录 #
text
app/javascript/
├── application.js # 主入口文件
├── controllers/ # Stimulus控制器
│ ├── application.js
│ ├── index.js
│ └── hello_controller.js
└── custom/ # 自定义JavaScript
└── utils.js
application.js:
javascript
// app/javascript/application.js
import "@hotwired/turbo-rails"
import "./controllers"
// 自定义代码
document.addEventListener("turbo:load", () => {
console.log("Page loaded!")
})
Stimulus控制器:
javascript
// app/javascript/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.element.textContent = "Hello World!"
}
}
2.7 assets目录 #
text
app/assets/
├── stylesheets/
│ ├── application.css
│ ├── articles.css
│ └── components/
│ ├── buttons.css
│ └── forms.css
├── images/
│ ├── logo.png
│ └── icons/
└── builds/ # 编译后的资源
2.8 mailers目录 #
text
app/mailers/
├── application_mailer.rb # 基础邮件器
└── user_mailer.rb # 用户邮件器
邮件器示例:
ruby
# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: "noreply@myapp.com"
layout 'mailer'
end
# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
def welcome_email(user)
@user = user
mail(to: @user.email, subject: '欢迎加入')
end
end
2.9 jobs目录 #
text
app/jobs/
├── application_job.rb # 基础任务
├── cleanup_job.rb # 清理任务
└── notification_job.rb # 通知任务
任务示例:
ruby
# app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base
# 自动重试
retry_on StandardError, wait: 5.seconds, attempts: 3
end
# app/jobs/cleanup_job.rb
class CleanupJob < ApplicationJob
queue_as :default
def perform(*args)
# 执行清理任务
Article.where('created_at < ?', 1.year.ago).destroy_all
end
end
三、config目录 #
3.1 config目录结构 #
text
config/
├── application.rb # 应用配置
├── boot.rb # 启动配置
├── environment.rb # 环境配置
├── environments/ # 各环境配置
│ ├── development.rb
│ ├── test.rb
│ └── production.rb
├── initializers/ # 初始化器
│ ├── assets.rb
│ ├── content_security_policy.rb
│ ├── filter_parameter_logging.rb
│ ├── inflections.rb
│ └── permissions_policy.rb
├── locales/ # 国际化文件
│ ├── en.yml
│ └── zh.yml
├── routes.rb # 路由配置
├── database.yml # 数据库配置
├── storage.yml # 存储配置
├── puma.rb # Puma服务器配置
└── credentials.yml.enc # 加密凭证
3.2 核心配置文件 #
application.rb:
ruby
# config/application.rb
require_relative "boot"
require "rails/all"
Bundler.require(*Rails.groups)
module Myapp
class Application < Rails::Application
# 初始化时加载
config.load_defaults 7.1
# 时区设置
config.time_zone = "Beijing"
# 默认语言
config.i18n.default_locale = :zh
# 自动加载路径
config.autoload_paths << Rails.root.join('lib')
# 生成器配置
config.generators do |g|
g.orm :active_record
g.test_framework :rspec
g.stylesheets false
g.javascripts false
g.helper false
end
end
end
routes.rb:
ruby
# config/routes.rb
Rails.application.routes.draw do
# 根路由
root 'home#index'
# RESTful资源
resources :articles
# 嵌套资源
resources :articles do
resources :comments
end
# 命名空间
namespace :admin do
resources :users
end
# 自定义路由
get 'about', to: 'pages#about'
post 'login', to: 'sessions#create'
end
database.yml:
yaml
# config/database.yml
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
production:
<<: *default
database: myapp_production
username: myapp
password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
3.3 环境配置 #
development.rb:
ruby
# config/environments/development.rb
Rails.application.configure do
config.cache_classes = false
config.eager_load = false
config.consider_all_requests_local = true
config.server_timing = true
config.action_controller.perform_caching = false
config.active_storage.service = :local
config.action_mailer.raise_delivery_errors = false
config.active_support.deprecation = :log
config.active_record.migration_error = :page_load
config.assets.debug = true
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
production.rb:
ruby
# config/environments/production.rb
Rails.application.configure do
config.cache_classes = true
config.eager_load = true
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.assets.compile = false
config.log_level = :info
config.log_tags = [:request_id]
config.action_mailer.perform_caching = false
config.active_support.deprecation = :notify
config.log_formatter = ::Logger::Formatter.new
config.active_record.dump_schema_after_migration = false
end
3.4 初始化器 #
ruby
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'person', 'people'
inflect.uncountable %w[fish sheep]
end
# config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]
四、db目录 #
4.1 db目录结构 #
text
db/
├── migrate/ # 迁移文件
│ ├── 20240328000001_create_articles.rb
│ └── 20240328000002_create_comments.rb
├── schema.rb # 数据库结构
├── seeds.rb # 种子数据
└── development.sqlite3 # SQLite数据库文件
4.2 迁移文件 #
ruby
# db/migrate/20240328000001_create_articles.rb
class CreateArticles < ActiveRecord::Migration[7.1]
def change
create_table :articles do |t|
t.string :title
t.text :body
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :articles, :title
end
end
4.3 种子数据 #
ruby
# db/seeds.rb
# 创建用户
User.create!(
email: 'admin@example.com',
password: 'password',
admin: true
)
# 创建文章
10.times do |i|
Article.create!(
title: "文章 #{i + 1}",
body: "这是第 #{i + 1} 篇文章的内容..."
)
end
五、其他目录 #
5.1 lib目录 #
text
lib/
├── tasks/ # Rake任务
│ └── cleanup.rake
├── myapp/ # 自定义库
│ └── utils.rb
└── templates/ # 自定义模板
Rake任务示例:
ruby
# lib/tasks/cleanup.rake
namespace :cleanup do
desc "清理过期文章"
task articles: :environment do
Article.where('created_at < ?', 1.year.ago).destroy_all
puts "清理完成"
end
end
# 运行:rails cleanup:articles
5.2 public目录 #
text
public/
├── 404.html # 404错误页面
├── 422.html # 422错误页面
├── 500.html # 500错误页面
├── robots.txt # 搜索引擎配置
└── favicon.ico # 网站图标
5.3 test目录 #
text
test/
├── controllers/ # 控制器测试
├── models/ # 模型测试
├── integration/ # 集成测试
├── fixtures/ # 测试数据
├── helpers/ # 辅助方法测试
└── test_helper.rb # 测试配置
5.4 vendor目录 #
text
vendor/
└── javascript/ # 第三方JavaScript
└── bootstrap.js
六、文件命名规范 #
6.1 命名规则 #
| 类型 | 文件名 | 类名/模块名 |
|---|---|---|
| 模型 | user.rb | User |
| 控制器 | users_controller.rb | UsersController |
| 辅助方法 | users_helper.rb | UsersHelper |
| 邮件器 | user_mailer.rb | UserMailer |
| 任务 | cleanup_job.rb | CleanupJob |
| 迁移 | 20240328000001_create_users.rb | CreateUsers |
| 部分视图 | _form.html.erb | - |
| 布局 | application.html.erb | - |
6.2 命名约定 #
| 规则 | 示例 |
|---|---|
| 类名使用驼峰命名 | OrderItem |
| 文件名使用蛇形命名 | order_item.rb |
| 表名使用复数 | order_items |
| 外键使用单数_id | order_id |
| 控制器使用复数 | OrdersController |
七、总结 #
7.1 核心目录 #
| 目录 | 作用 |
|---|---|
| app/ | 应用核心代码(MVC) |
| config/ | 配置文件 |
| db/ | 数据库相关 |
| lib/ | 扩展库和任务 |
| public/ | 公共静态文件 |
| test/ | 测试文件 |
7.2 下一步 #
现在你已经了解了Rails项目结构,接下来让我们学习 路由基础,深入了解Rails的路由系统!
最后更新:2026-03-28