Ruby on Rails - 控制器
Ruby on Rails - 控制器(Controllers)
Section titled “Ruby on Rails - 控制器(Controllers)”控制器(Controller)是 Rails 应用中 MVC 模式的 ‘C’。它充当用户(通过路由和视图)与应用数据(模型)之间的中介。控制器处理接收到的 Web 请求,使用模型检索或修改数据,然后通过选择一个视图模板来渲染响应。
控制器的主要职责:
- 从路由接收 HTTP 请求。
- 与模型交互,用于获取、创建、更新或删除数据。
- 管理会话(session)信息和 Cookie。
- 处理用户身份验证和授权(通常借助辅助 Gem)。
- 通过实例变量(例如
@books)将数据提供给视图(view)。 - 选择要渲染的视图模板或要重定向(redirect)到的 URL。
您可以使用 Rails 生成器(generator)来创建控制器。对于我们的图书馆应用,让我们创建一个 BooksController:
$ bin/rails generate controller Books index show new edit create update destroy按照惯例,控制器名称是复数形式并使用驼峰命名法(CamelCased)(例如,BooksController)。此命令会创建:
app/controllers/books_controller.rb文件。- 指定动作(action)的视图模板文件(例如,
app/views/books/index.html.erb)。 - 测试文件、辅助方法(helper)文件以及可能的资源文件(asset files)。
- 如果
config/routes.rb中不存在,它还会为books添加 RESTful 风格的路由(resourceful routes)。
生成的 app/controllers/books_controller.rb 大致如下所示:
class BooksController < ApplicationController def index end
def show end
# ... other generated actions ...end控制器类继承自 ApplicationController(在 app/controllers/application_controller.rb 中定义),这是放置应用范围的控制器逻辑(如身份验证或布局设置)的好地方。
实现控制器动作 (CRUD 示例)
Section titled “实现控制器动作 (CRUD 示例)”让我们为 BooksController 实现常见的 CRUD (Create, Read, Update, Delete) 动作。
index 动作 (列出所有书籍)
Section titled “index 动作 (列出所有书籍)”index 动作通常显示资源列表。
def index @books = Book.all.order(title: :asc) # 获取所有书籍,按标题排序 # Rails 将自动渲染 app/views/books/index.html.erbendshow 动作 (显示单本书)
Section titled “show 动作 (显示单本书)”show 动作显示单个资源的详细信息,通过 params[:id] 标识。
before_action :set_book, only: [:show, :edit, :update, :destroy]# ...def show # @book 由 set_book before_action 设置 # 渲染 app/views/books/show.html.erbend# ...private
def set_book @book = Book.find(params[:id])rescue ActiveRecord::RecordNotFound flash[:alert] = "The book you were looking for could not be found." redirect_to books_pathendbefore_action :set_book 会在指定的动作之前调用 set_book 方法。这减少了查找书籍的代码重复(DRY - Don’t Repeat Yourself)。对 RecordNotFound 的错误处理是良好的实践。
new 动作 (新建书籍表单)
Section titled “new 动作 (新建书籍表单)”new 动作准备一个空的 @book 对象,用于新建书籍表单。
def new @book = Book.new @subjects = Subject.all.order(:name) # 用于表单中的主题下拉列表 # 渲染 app/views/books/new.html.erbendcreate 动作 (保存新建书籍)
Section titled “create 动作 (保存新建书籍)”create 动作处理来自 new 表单的提交,并尝试保存新书。
def create @book = Book.new(book_params) if @book.save redirect_to @book, notice: 'Book was successfully created.' # 重定向到显示页面 else @subjects = Subject.all.order(:name) # 如果重新渲染表单,重新加载主题数据 render :new, status: :unprocessable_entity # 重新渲染 new 表单并显示错误 endendbook_params 是一个私有方法,它使用 Strong Parameters(强参数)仅允许指定的属性,从而防止批量赋值(mass assignment)漏洞。
Strong Parameters (强参数)
Section titled “Strong Parameters (强参数)”private
def book_params params.require(:book).permit(:title, :price, :subject_id, :description, :published_at)endedit 动作 (编辑书籍表单)
Section titled “edit 动作 (编辑书籍表单)”edit 动作获取一本现有书籍(使用 set_book 方法),用于编辑表单。
def edit # @book 由 set_book 设置 @subjects = Subject.all.order(:name) # 渲染 app/views/books/edit.html.erbendupdate 动作 (保存书籍更改)
Section titled “update 动作 (保存书籍更改)”update 动作处理来自 edit 表单的提交。
def update # @book 由 set_book 设置 if @book.update(book_params) redirect_to @book, notice: 'Book was successfully updated.' else @subjects = Subject.all.order(:name) render :edit, status: :unprocessable_entity endenddestroy 动作 (删除书籍)
Section titled “destroy 动作 (删除书籍)”destroy 动作删除一本书。
def destroy # @book 由 set_book 设置 @book.destroy redirect_to books_url, notice: 'Book was successfully destroyed.', status: :see_otherendstatus: :see_other (HTTP 303) 推荐用于在改变状态的非 GET 请求后进行重定向,尤其是在使用 Turbo 时。
完整的 BooksController 示例:
Section titled “完整的 BooksController 示例:”class BooksController < ApplicationController before_action :set_book, only: [:show, :edit, :update, :destroy] before_action :load_subjects, only: [:new, :edit, :create, :update] # 为表单加载主题数据
def index @books = Book.includes(:subject).all.order(title: :asc) end
def show end
def new @book = Book.new end
def edit end
def create @book = Book.new(book_params) if @book.save redirect_to @book, notice: 'Book was successfully created.' else render :new, status: :unprocessable_entity end end
def update if @book.update(book_params) redirect_to @book, notice: 'Book was successfully updated.' else render :edit, status: :unprocessable_entity end end
def destroy @book.destroy redirect_to books_url, notice: 'Book was successfully destroyed.', status: :see_other end
# Example custom action for listing books by subject (if needed here) # 例如,用于按主题列出书籍的自定义动作(如果需要) # def books_by_subject # @subject = Subject.find(params[:subject_id]) # @books = @subject.books.order(title: :asc) # render :index # Or a custom view like 'books_by_subject.html.erb' # # 渲染 :index 或自定义视图如 'books_by_subject.html.erb' # end
private
def set_book @book = Book.find(params[:id]) rescue ActiveRecord::RecordNotFound flash[:alert] = "The book you were looking for could not be found." redirect_to books_path end
def load_subjects @subjects = Subject.all.order(:name) end
def book_params params.require(:book).permit(:title, :price, :subject_id, :description, :published_at) endend现在,这个控制器处理了书籍资源(resource)的完整生命周期。
下一步是什么?
Section titled “下一步是什么?”定义好控制器动作后,您需要定义路由(route)将 URL 映射到这些动作。然后,您将创建视图模板(view template)来显示信息和表单以便用户交互。