【问题标题】:ActiveRecord#exists? or rescue from ActiveRecord::RecordNotFoundActiveRecord#存在吗?或从 ActiveRecord::RecordNotFound 救援
【发布时间】:2013-02-05 04:01:24
【问题描述】:

处理以下类型情况的推荐方法是什么:

假设我有一个名为Cart 的模型,它与模型Person 和相同的PK(用户ID)具有1-1 关系。

在我的cart_controllerindex 方法中,我想检查当前用户是否存在Cart。 如果我执行Cart.find(the_user_id) 并且购物车不存在,则会引发RecordNotFound 异常。
我看到了两种解决方法:

1。从异常中解救

 begin
    @cart = Cart.find(the_user_id)
    #more code here
 rescue ActiveRecord::RecordNotFound
    #the cart is empty message
 end

2。使用 ActiveRecord#exists?方法

 if Cart.exists?(the_user_id)
    @cart = Cart.find(the_user_id)
    #more code here
 else
    #the cart is empty message
 end

根据我对异常处理的(有限)知识,我知道不建议以这种方式使用异常,但每次都进行额外的查询值得吗?

【问题讨论】:

    标签: ruby-on-rails exception activerecord


    【解决方案1】:

    使用 find_by_id 代替 find:

    @cart = Cart.find_by_id(params[:id])
    

    如果它不存在则为零,因此您可以根据需要在控制器/视图中检查“if @cart”

    【讨论】:

    • +1 有趣。很高兴知道。谢谢。不过在这种情况下,我会选择@user.cart。
    • John 的答案比我的更接近您的问题域,但如果模型不属于另一个模型(即是单例模型或根模型),请将 if 视为额外工具
    • 这里有一些讨厌的 hack。爱它! +1
    【解决方案2】:

    您可以尝试向用户对象询问其购物车。假设您将用户分配给@user,那么如果用户有购物车,它将是@user.cart。如果@user.cartnil,那么他们没有。

    这假设您已正确设置模型之间的关系。

    【讨论】:

    • +1,好的。在这种情况下,这听起来是最好的方法。不幸的是我的问题#exists? vs救援没有得到持续的争论,我希望得到很好的答案
    • 不确定你所说的持续争论是什么意思。如果你使用 cart = Cart.find(:id) 那么如果它没有找到你会得到一个错误,你必须使用救援来捕获它。如果您使用 cart = Cart.find_by_id(:id) 那么 cart 将为 nil ,您可以对其进行测试。 @user.cart 将为 nil 或很容易测试的购物车。你可以这样做 if @cart = @user.cart #do cart stuff else # do no cart stuff end
    • 是的,在这种情况下,这绝对是最好的做法。但是我正在考虑一个一般情况,当我必须直接调用模型(无关联)(例如通过 id 查找)时。似乎我也得到了答案,使用 find_by_id,它不会引发 execption。
    • 实际上在你的情况下你需要使用 Cart.find_by_user_id(user_id)
    【解决方案3】:

    你为什么不做类似的事情......

    @cart = @user.cart || @user.cart.new
    

    不用担心异常或 if/else 语句。 那么在您看来,您可能会有类似...

    <% if @cart.empty? # or whatever method you use to determine 
         # if there is nothing in the cart...maybe .blank? is fine? 
    %>
        <p>Your cart is empty</p>
    <% else %>
        <!-- loop through objects in your cart -->
    <% end %>
    

    【讨论】:

    • +1 是的,@user.cart 是要做的事情,而不是直接调用 Cart 模型。不过我接受了李欧文的回答,因为他是第一个
    • 这应该是@user.build_cart
    【解决方案4】:

    存在吗?会导致多一条 SQL 语句,除非 ActiveRecord 的人对此进行了优化(我不会指望这一点)。

    所以我建议使用异常,它比 SQL 语句便宜得多。

    【讨论】:

    • ActiveRecord 现在有一个很好的查询缓存。你真的不应该对控制流使用异常。
    • 同意,没有必要例外,因为这并不是一个真正的例外情况,它很可能会发生很多。
    • 另外,性能方面,.create + rescue RecordNotUnique 将实例化 AR 对象并尝试在存在时使用 SQL 查询创建?在初始化新对象之前将运行非常简单、简短的查询。另一方面,如果重复记录的可能性很低,通常使用救援的方法可能更快。
    猜你喜欢
    • 1970-01-01
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    相关资源
    最近更新 更多