用于操作(更新、删除等)和错误检查的 Rails 模式

Posted

技术标签:

【中文标题】用于操作(更新、删除等)和错误检查的 Rails 模式【英文标题】:Rails pattern for action(update, delete, etc) & error checking 【发布时间】:2014-05-04 17:35:42 【问题描述】:

我是 Rails 的新手,所以我想知道下面是否存在已知模式(我的 Google 技能在这里失败了)。

我所有的 Rest 控制器都遵循以下基本模式:

检查项目是否存在 --> 如果存在则获取项目 --> 如果不存在则返回错误 --> 如果存在则执行某些操作 --> 检查操作是否失败 --> 如果失败则返回错误--> 如果没有,则成功。所以两个动作,两个错误检查。我的问题是:这是一个很好的正确模式,还是我应该做一些不同的事情?

“销毁”方法示例:

def destroy 
  if @team = fetch_team
    if @team.destroy
      render json: message: "team: '#params[:id]' deleted", status: 200
    else
      render json: message: "error: #@team.errors.full_messages", status: 500
    end          
  else
    render json: message: "team: '#params[:id]' not found", status: 404  
  end
end

##

def fetch_team
    Team.find_by(name: params[:id])
end

【问题讨论】:

【参考方案1】:

我会从单个操作中重构您的一些逻辑,使其更干燥。

首先,我会将fetch_team 的检查移到before_action 过滤器中。这样一来,您就可以让 Rails 为多个操作运行它,例如 showupdatedestroy

当你调用Team.find_by!(注意爆炸)时,如果没有找到记录,Rails 将抛出一个ActiveRecord::RecordNotFound 异常。因此,如果没有找到记录,您可以使用rescue_from 执行您需要执行的操作。这样一来,您就无需在多个操作中重复该逻辑。

class TeamsController < ApplicationController
  before_action :find_team, only: [:show, :update, :destroy]
  rescue_from ActiveRecord::RecordNotFound, with: :not_found # This can be moved to `ApplicationController` if you follow this pattern in ALL of your controllers

  def destroy
    if @team.destroy
      render json:  message: "team: '#params[:id]' deleted" , status: 200
    else
      render json:  message: "error: #@team.errors.full_messages" , status: 500
    end
  end

private

  def find_team
    @team = Team.find_by!(name: params[:id])
  end

  def not_found
    render json:  message: "team: '#params[:id]' not found" , status: 404
  end
end

说了这么多,我觉得not_found中的定义是非常大方的。通常,当find_by! 失败时,我会让控制器抛出它自己的 404 异常,并期望客户端能够识别 404 标头并做出相应的响应。如果您希望显示示例中的错误消息,这取决于您。

【讨论】:

这看起来好多了,谢谢。但是似乎我需要ActiveRecord::RecordNotFound 而不是ActiveRecord::NotFound 编辑了我的答案。你有证据证明我在浏览器中编码了整个答案。至少我是一致的。 :)【参考方案2】:

让我们使用销毁操作示例:

我见过的常见方法是让控制器销毁动作像这样简单:

def destroy
  @team = Team.find(params[:id]) # first find the object you want to delete 
  @team.destroy # if it's found, call the destroy method on it. if it's not found, you won't get to this line. it'll raise error. 
  respond_to do |format|
    format.html  redirect_to teams_url  #this is redirecting to your chosen path once it's destroyed. 
    format.json  head :no_content 
  end
end

但在您看来,您将在继续删除之前为用户提供改变主意的机会:

app/views/teams/show.html.erb

<%= link_to 'Delete team', @team class: 'btn btn-primary', method: :delete, data:  confirm: 'Are you sure you want to delete this team?'  %>

这将提示弹出消息。他们可以点击cancel或点击ok继续删除

【讨论】:

以上是关于用于操作(更新、删除等)和错误检查的 Rails 模式的主要内容,如果未能解决你的问题,请参考以下文章

Rails ajax 调用同时产生 404 和 500 错误

Ajax 和 Rails 4:创建实例变量并更新视图而不刷新

Rails 5:更新操作不适用于 AJAXified 表单

ruby 用于检查rails_admin实现中的自定义操作的集成测试

Rails 视图在删除链接中传递了错误的参数

Rails在破坏行动后重定向