Rails CRUD 路由和控制器方法最佳实践

Rails CRUD route and controller method best practices

CRUD 代表创建、读取、更新、删除。这是四种方法(如果区分查看一条记录和查看所有记录,则为五种方法)。在 Rails 中,处理 CRUD 的规范方法似乎涉及七种方法。例如,使用 resources :orders shorthand 为 Order 对象创建路由会生成以下七个路由:

这是我困惑的根源。 new/createedit/update 分开 actions/routes 有什么意义?使用单独的操作来查看页面与在数据库中创建记录有什么好处?我了解 如何 在 Rails 中完成,例如:

class OrdersController < ApplicationController
  def new
    @order = Order.new
    render
  end

  def create
    @order = Order.new(order_params)
    if @order.save
      redirect_to @order, notice: 'Successfully created an order.'
    else
      render :new
    end
  end
end

在使用 Rails 之前,我使用了 Yii (PHP),它有一个内置的 CRUD 生成器,可以生成如下代码(翻译为 Rails):

class OrdersController < ApplicationController

  def create

    if request.method == "POST"
      @order = Order.new(order_params)
      if @order.save
        redirct_to @order, notice: 'Successfully created an order.'
      end
    else
      @order = Order.new
    end

    render 

  end
end

我更喜欢这种模式的原因是因为它避免了为不同的控制器操作呈现模板。在第一个代码示例中,用户转到 orders/new 并发布到 orders/create。如果验证失败,用户仍停留在 orders/create,但正在查看 orders/new 的模板。这可能会使用户感到困惑,而且它似乎也破坏了使用单独的操作来查看页面与在数据库中创建记录的整个想法。如果您重定向到 orders/new 而不是使用 render :new 那么您将丢失所有验证错误消息。

我发现自己在 Rails 代码中下意识地回到了 Yii 方式。谁能解释为什么标准方式是有利的?如果我偏离规范的 Rails 模式,我会 运行 遇到什么问题吗?

Whosebug 警告我这个问题是主观的,可能会被关闭,所以让我澄清一下。我不是要争论 Rails 与 Yii 或确定组织 CRUD 代码的最佳理论方法。我想知道如果我偏离规范的 Rails 处理 CRUD 的方式,Rails 是否有任何问题会中断。

简单的解释就是:

because that's how God and DHH intended it.

Rails CRUD 约定非常实用,可以让您避免许多与浏览器缓存和安全相关的陷阱。

举个例子:

# config/routes.rb
resources :users, only: [:new, :create]

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)

    if @user.save
      sign_in(@user)
      redirect_to root_path
    else
      render :new
    end
  end

  private 
    def user_params
      params.require(:user).permit(:email, :password, :password_confirmation)
    end
end

这里我们有两条独立的路线GET /users/newPOST /users

第一个路由是幂等的——它对任何访问者来说都应该是一样的并且可以被缓存。第二个不是 - 它应该显示创建或尝试创建资源的结果。

当用户访问 /users/new 我们 POST 表单到不同的 URI。这避免了客户端中的历史问题。

如果输入无效,我们也会在同一请求周期中呈现表单。这避免了如果我们尝试将表单数据重定向回 /users/new 并让我们 return 语义正确的响应代码而不是重定向时可能出现的安全问题。

它还确保我们的应用程序在 restful 意义上是无状态的,因为之前的操作不会影响我们访问 /users/new 时看到的内容。

在体系结构级别,它允许您利用约定优于配置。你可以这样做:

def new
  @user = User.new
end

它会呈现 views/users/new.html.erb 因为 Rails 可以推导出新操作应该呈现新模板。从设计和测试的角度来看,让每个控制器操作执行一项任务要好得多,因为它消除了在同一方法中测试两个独立代码路径的需要。