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