学习目标:掌握 ActionController 的核心功能和最佳实践
1. Controller 基础#
1.1 基本结构#
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
@posts = Post.all
end
def show
end
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: 'Post was successfully created.'
else
render :new
end
end
private
def set_post
@post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
end
1.2 Action 执行流程#
1. before_action 回调
↓
2. 执行 action 方法
↓
3. 渲染视图或重定向
↓
4. after_action 回调
2. Filters(过滤器)#
2.1 before_action#
class ApplicationController < ActionController::Base
before_action :authenticate_user!
before_action :set_locale
private
def authenticate_user!
redirect_to login_path unless current_user
end
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
2.2 skip_before_action#
class PublicController < ApplicationController
skip_before_action :authenticate_user!
end
2.3 around_action#
around_action :benchmark
def benchmark
start_time = Time.now
yield
duration = Time.now - start_time
logger.info "Action took #{duration}ms"
end
3. 渲染和重定向#
3.1 render 选项#
# 渲染模板
render :index
render 'posts/index'
render template: 'posts/index'
# 渲染文本
render plain: "Hello"
# 渲染 JSON
render json: @post
render json: @post, status: :created
# 渲染 XML
render xml: @post
# 渲染文件
render file: "/path/to/file"
# 局部模板
render partial: 'form'
render partial: 'post', collection: @posts
# 状态码
render :new, status: :unprocessable_entity
3.2 redirect_to#
# 重定向到 URL
redirect_to posts_path
redirect_to @post
redirect_to root_url
# 带状态码
redirect_to @post, status: :moved_permanently
# 带 flash
redirect_to @post, notice: "Success!"
redirect_to @post, alert: "Error!"
# redirect_back
redirect_back(fallback_location: root_path)
4. Strong Parameters#
4.1 基本用法#
def post_params
params.require(:post).permit(:title, :content, :published)
end
# 嵌套参数
def user_params
params.require(:user).permit(
:name,
:email,
profile_attributes: [:bio, :avatar],
addresses_attributes: [:street, :city, :_destroy]
)
end
# 数组参数
def post_params
params.require(:post).permit(:title, tag_ids: [])
end
4.2 自定义清理#
def user_params
permitted = params.require(:user).permit(:name, :email)
permitted[:email] = permitted[:email].downcase if permitted[:email]
permitted
end
5. Rescue 错误处理#
5.1 rescue_from#
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from User::NotAuthorized, with: :user_not_authorized
private
def record_not_found
render plain: "404 Not Found", status: 404
end
def user_not_authorized
flash[:error] = "You are not authorized to perform this action."
redirect_to root_path
end
end
6. HTTP 认证#
6.1 Basic 认证#
class AdminController < ApplicationController
http_basic_authenticate_with name: "admin", password: "secret"
end
6.2 Token 认证#
before_action :authenticate_with_token
def authenticate_with_token
authenticate_or_request_with_http_token do |token, options|
User.find_by(api_token: token)
end
end
7. Streaming#
7.1 文件下载#
def download
send_file '/path/to/file.pdf',
filename: 'document.pdf',
type: 'application/pdf',
disposition: 'attachment'
end
# 发送数据
def export
send_data generate_csv(@posts),
filename: 'posts.csv',
type: 'text/csv'
end
7.2 实时流式传输#
def stream
response.headers['Content-Type'] = 'text/event-stream'
10.times do |i|
response.stream.write "data: #{i}\n\n"
sleep 1
end
ensure
response.stream.close
end
8. 控制器组织#
8.1 Concerns#
# app/controllers/concerns/authenticable.rb
module Authenticable
extend ActiveSupport::Concern
included do
before_action :authenticate_user!
end
private
def authenticate_user!
redirect_to login_path unless current_user
end
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
end
# 使用
class PostsController < ApplicationController
include Authenticable
end
9. 测试#
9.1 Controller 测试#
class PostsControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get posts_url
assert_response :success
end
test "should create post" do
assert_difference('Post.count') do
post posts_url, params: { post: { title: "Test", content: "Content" } }
end
assert_redirected_to post_url(Post.last)
end
end
10. 本章总结#
ActionController 提供了:
- Filters 和回调系统
- 渲染和重定向
- Strong Parameters 安全参数过滤
- 错误处理
- HTTP 认证
- 文件下载和流式传输
上一篇:路由系统深入 下一篇:ActionView 渲染 返回:学习指南首页