CRUD代表创建,读取,更新,删除。这是四种方法(如果您区分查看一条记录和查看所有记录,则为五种方法)。在Rails中,处理CRUD的规范方法似乎涉及七种方法。例如,使用resources :orders
速记为Order对象创建路由会生成以下七个路径:
这是我困惑的根源。为new
/ create
和edit
/ update
分别采取行动/路线的重点是什么?使用单独的操作查看页面与在数据库中创建记录有什么好处?我理解如何在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模式,是否会遇到任何问题?
StackOverflow警告我这个问题是主观的,可能会被关闭,所以让我澄清一下。我不是要讨论Rails vs. Yii或确定组织CRUD代码的最佳理论方法。我想知道如果我偏离规范的Rails处理CRUD的方式,Rails有什么会破坏。
答案 0 :(得分:3)
简单的解释是:
因为这就是上帝和DHH的意图。
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/new
和POST /users
。
第一条路线是幂等的 - 它对于任何访客都应该看起来相同并且可以被缓存。第二个不是 - 它应该显示创建或尝试创建资源的结果。
当用户访问/users/new
时,我们会将表单发布到其他URI。这避免了客户端的历史问题。
如果输入无效,我们还会在同一请求周期中呈现表单。这样可以避免在我们尝试将表单数据重定向回/users/new
时出现的安全问题,并让我们返回语义正确的响应代码而不是重定向。
它还确保我们的应用程序在宁静的意义上是无状态的,因为如果我们访问/users/new
,之前的操作不会影响我们看到的内容。
在架构级别,它允许您利用约定优于配置。你可以这样做:
def new
@user = User.new
end
它将呈现views/users/new.html.erb
,因为Rails可以推导出新动作应该呈现新模板。从设计和测试的角度来看,让每个控制器操作执行一个单独的任务要好得多,因为它不需要在同一个方法中测试两个单独的代码路径。