【问题标题】:Should we use strong params when we update only one attribute?当我们只更新一个属性时,我们应该使用强参数吗?
【发布时间】:2016-01-10 18:22:17
【问题描述】:

我正在开发一个 Rails 应用程序,我有几个操作(#delete_later、#ban_later 等),我只从请求参数中设置一个属性(特别是用于执行该操作的 reason 字段)。

我想知道这样做是否可以:

def ban_later
  @object.reason = params[:object][:reason]
  @object.save
end

或者即使在这种情况下也使用强参数是一种最佳做法?

def ban_later
  @object.reason = object_params[:reason]
  @object.save
end

private
  def object_params
    params.require(:object).permit(:permitted_1, :permitted_2, :reason)
  end

这些解决方案中哪一个是最好的?如果它们都不是,那么我的问题的最佳解决方案是什么?

后期编辑:

#ban_later、#delete_later 操作确实可以设置标志列status,但这可以在不从 params 哈希中接收其值的情况下完成。由于您只会为每个方法设置一个状态,因此您可以在#delete_later 中设置状态“pending_delete”,在#ban_later 中设置“pending_ban”。

稍后编辑

为什么直接使用#save 而不是update_attributes?假设您需要有一个if @object.save 声明。在错误分支(对象未保存)上,您可能仍希望呈现一个使用 @object 内容的视图。

【问题讨论】:

    标签: ruby-on-rails ruby strong-parameters mass-assignment


    【解决方案1】:

    强参数检查后为什么不只是update对象?它只是一个标准的工作流程。 (请告诉我在您的情况下是否有任何理由不这样做)

    def ban_later
      @object.update(object_params)
      # dont forget validation check
    end
    
    private
      def object_params
        params.require(:object).permit(:permitted_1, :permitted_2, :reason)
      end
    

    在这种情况下,添加更多可更新字段会容易得多。

    【讨论】:

    • 你想要一个if @object.save 声明。在错误的分支(对象未保存)上,您可能仍希望呈现一个使用 @object 内容的视图。
    • @Dmitri,有什么问题吗?在update 失败后,是什么阻止您渲染@object
    • 如果更新失败,AFAIK,@object 将包含数据库中的值。我可能希望它包含来自参数的新值。把它想象成一个需要验证的表单。如果某个字段的验证失败,您希望使用您编写的值重新呈现表单,而不是保存到数据库中的值。
    • 另一方面,如果您逐个更新字段,@object 将包含新值。
    • @Dmitri,我认为你错了。验证失败后,@object 仍将处于无效状态且字段无效
    【解决方案2】:

    如果您要更新 单个 属性,为什么不使用 update_attributes 方法? (update_attribute 不调用验证)

    def ban_later
      @object.update_attributes reason: params(:reason)
    end
    
    private
    
    def params params
        params = %i(:permitted_1, :permitted_2, :permitted_3) unless params
        params.require(:object).permit params
    end
    

    根据ReggieB 的cmets,您还可以使用update 选项:

    def ban_later
        @object.update reason: params(:reason)
    end 
    

    如前所述,Reggie 和其他答案解释了其最佳工作原理的示意图(IE 与 mass-assignment 等)。以上是您可以免费使用的可操作代码。


    这里的底线是,如果您想让您的应用程序保持通用性(IE 在任何您需要的地方都具有最终的可扩展性),您需要遵守 strong params 设置。

    其他答案概述了该设置的工作原理,以及它的功能如何根据您的需要而有所不同。

    我已经包含了一个技巧,所以你只接受你的 params 方法中的特定参数。我没有对它进行广泛的测试,因此我们可能需要对其进行重构以获得所需的结果。

    【讨论】:

    • method=save 相比,它在一行中的表现如何,否则需要两个。
    • 是的 - 在我写完最初的评论后,我注意到了您对 update_attribute 的评论。我仍然认为使用 update_attributes 来更新单个属性并不是一个好的模式——尤其是当开发人员质疑是否使用强参数时。
    • 可能 - 我提出了我的建议。他也可以使用update,我将添加到答案中
    • 关键是“这里的底线是,如果你想保持你的应用程序的多功能......,你需要坚持强大的参数设置。”仍然不喜欢你在做什么,但我已经删除了我的反对票。
    • 如果您不喜欢它,请继续投反对票。我尽可能提供代码,如果代码错了,那就错了。我宁愿提出代码并让它出错,而不是让 OP 猜测。很高兴您指出了系统的这样一个内在部分。我在批量分配等方面没有超级经验,这就是为什么我概述了您的答案和其他答案在系统示意图方面要好得多。无论你是否同意,我都是不偏不倚的,我提出答案是为了保持我自己的技能^_^
    【解决方案3】:

    最简单的答案是,如果您只使用params 中的一个参数,并且不将其传递给像model#create 这样的多属性设置器,那么您不必使用strong_parameters 来获得安全的解决方案。

    但是,我预计整个控制器不太可能出现这种情况。 ban_later 方法只需要一个参数,其他控制器方法需要更多参数。在这种情况下,问题就变成了:“您想对ban_later 以不同的方式处理params,以将其用于其他控制器方法吗?”。

    您还可以确保功能不会改变,并且当您更改功能时,您会记得更改params 的处理方式。

    因此,我会使用 strong_parameters,因为它意味着:

    • 在控制器中的所有方法中一致地处理参数。
    • 对方法的更改不太可能在功能更改时暴露漏洞。

    【讨论】:

    • 好吧,#ban_later,#delete_later 确实可以设置一个标志列status,但这可以在不从 params 散列接收它的值的情况下完成。由于您只会为每个方法设置一个状态,因此您只需在#delete_later 中设置状态“pending_delete”,在#ban_later 中设置“pending_ban”。
    • 如您所见,除了执行特定操作的原因之外,您不需要用户提供任何参数。
    • 你是对的。您不必使用strong_parameters。但出于我提出的原因,我愿意。
    【解决方案4】:

    第一个节省计算量。

    第二个检查是否存在 :object 子哈希,我认为这有利于容错。

    我最初会选择第一个,但经过一些思考后我更喜欢第二个。

    【讨论】:

      猜你喜欢
      • 2014-04-09
      • 2015-12-28
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      • 2017-07-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      相关资源
      最近更新 更多