【问题标题】:When creating an object in Ruby on Rails, which method of saving do you prefer, and why?在 Ruby on Rails 中创建对象时,您更喜欢哪种保存方法,为什么?
【发布时间】:2009-04-07 14:50:31
【问题描述】:

在为 Ruby on Rails 应用程序中的对象编写“创建”方法时,我使用了两种方法。为了更清晰和更一致的代码,我想使用一种方法。我将在下面列出这两种方法。有谁知道一个比另一个更好吗?如果有,为什么?

方法一:

def create1
  # is this unsecure? should we grab user_id from the session
  params[:venue]['user_id'] = params[:user_id]

  begin
    venue = Venue.create(params[:venue])
    @user_venues = @user.venues
    render :partial => 'venue_select_box', :success => true, :status => :ok
  rescue ActiveRecord::RecordInvalid
    render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
  end
end

方法二:

def create2
   # is this unsecure? should we grab user_id from the session
  params[:venue]['user_id'] = params[:user_id]

  venue = Venue.new(params[:venue])
  if venue.save
    @user_venues = @user.venues
    render :partial => 'venue_select_box', :success => true, :status => :ok
  else
    render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
  end
end

【问题讨论】:

  • 我想你的意思是“创造!”不是方法 1 中的“创建”。“创建”不会引发异常;它只是在验证错误时返回 false。
  • 你说得对,谢谢指出

标签: ruby-on-rails ruby activerecord rescue


【解决方案1】:
class VenuesController < ApplicationController
  def create
    @venue = @user.venues.create!(params[:venue])
    render :partial => 'venue_select_box', :success => true, :status => :ok
  end

  rescue_from ActiveRecord::RecordInvalid do
    render :text => 'Put errors in here', :success => false, :status => :unprocessable_entity
  end
end

以这种方式使用@user.venues 可确保始终正确设置用户ID。此外,ActiveRecord 将保护:user_id 字段在#create! 调用过程中不被赋值。因此,来自外部的攻击将无法修改:user_id

在您的测试中,您可以验证对 :create 执行 POST 会引发 ActiveRecord::RecordInvalid 异常。

【讨论】:

  • chaos 的观点是,“异常不应该用于常规条件”是一个很好的观点。然而 Rails 另有决定:“rescue_from ActiveRecord::RecordInvalid”是常见的做法。
【解决方案2】:

我认为例外不应该用于常规条件,所以我会说第二种更好。

【讨论】:

    【解决方案3】:

    这取决于。如果您希望所有的 create 语句都能正常工作,请使用前者,因为创建和保存失败是异常的,并且可能是程序无法轻松恢复的情况。此外,如果您使用关系完整性(RedHill Consulting 的foreign_key_migrations),这将引发外键违规异常,因此您可能希望在创建或更新时捕获它们。

    第二个是可行的,如果查询不成功是您期望作为该特定操作的日常操作的一部分的事情,那么这很好。

    另外,关于会话不安全的代码注释——会话是放置 user_id 的地方。只要您在执行任何其他操作之前检查以验证用户是否已通过身份验证,就可以了。

    【讨论】:

    • 既然这是一个创建操作,你是说如果我有客户端验证版本 1 很好,但如果我使用服务器端验证版本 2 更好?
    • 不完全...除了少数例外,您总是希望在服务器端进行验证,作为安全预防措施(客户端验证始终可以通过恶意攻击者)...(分成两个 cmets)
    • 我的经验法则是,当我预计操作可能完成而不会遇到数据库约束时,我使用 save(),而当我预计它可能完成时,我使用 create()...帮助?我也总是实现一个全局异常处理程序来捕获杂散错误。
    • 在您的回答中您说“如果您希望所有创建语句都可以工作,请使用(创建)”。在这里,您是说当您期望操作会遇到数据库约束时使用 create (我认为您的意思是失败)。另外,我正在考虑在客户端和服务器上都进行验证
    【解决方案4】:

    我完全同意唐的评论。但我什至会更进一步使用 user_id 部分并将其设置为模型上的前置过滤器。

    【讨论】:

      猜你喜欢
      • 2010-09-12
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 2010-09-14
      • 2023-01-11
      相关资源
      最近更新 更多