清理参数哈希时减少 AbcSize 指标

Reduce AbcSize metric when sanitizing params hash

我的 Purchases 控制器中有一个简单的方法,可以在应用强参数之前调整来自 params 哈希的用户表单输入。

def sanitize_params
  params[:purchase][:invoice] = nil if params[:purchase][:invoice] == ''
  params[:purchase][:note] = nil if params[:purchase][:note] == ''
  params[:purchase][:product_id] = nil if params[:purchase][:product_id].blank?
end

Rubocop 因 Metrics/AbcSize… [<3, 19, 5> 19.87/17] 被捕。 ABC指标中的‘Branch’如何计算为19?

我可以重构为:

def sanitize_params
  unsanitized_purchase_params = params[:purchase]
  params[:purchase][:invoice] = nil if unsanitized_purchase_params[:invoice] == ''
  params[:purchase][:note] = nil if unsanitized_purchase_params[:note] == ''
  params[:purchase][:product_id] = nil if unsanitized_purchase_params[:product_id].blank?
end

这就通过了,但是以可读性和额外代码为代价。 为什么'Branch'在原始代码中是19?我应该关心吗? (我的实际用例有一条额外的相似线,所以那里的指标更高)。有更好的方法吗? 谢谢 丹尼尔

目前 Rails 参数未实现 #deep_transform_values!,但您可以执行以下操作:

def sanitize_params
  %i[invoice note product_id].each do |param_name|
    params[:purchase][param_name] = params[:purchase][param_name].presence
  end
end

或者:

def sanitize_params
  params[:purchase] = params[:purchase].transform_values(&:presence)
end

更新。您还可以考虑使用 https://github.com/rmm5t/strip_attributes - 此 gem 将在模型级别

上用 nils 替换空值

documentation 给出:

Branch -- an explicit forward program branch out of scope -- a function call, class method call, or new operator

所以,ABC中的“Branch”计算为“跳出当前方法的任何东西”。

按照您描述的方法,

def sanitize_params
  params[:purchase][:invoice] = nil if params[:purchase][:invoice] == ''
  params[:purchase][:note] = nil if params[:purchase][:note] == ''
  params[:purchase][:product_id] = nil if params[:purchase][:product_id].blank?
end

这些是需要离开当前方法的 19 个调用:

01. params (on line 1, before the assignment)
02. params[:purchase] (on line 1, before the assignment)
03. params[:purchase][:invoice] (on line 1, before the assignment)
04. params (on line 1, after the assignment)
05. params[:purchase] (on line 1, after the assignment)
06. params[:purchase][:invoice] (on line 1, after the assignment)

07. params (on line 2, before the assignment)
08. params[:purchase] (on line 2, before the assignment)
09. params[:purchase][:note] (on line 2, before the assignment)
10. params (on line 2, after the assignment)
11. params[:purchase] (on line 2, after the assignment)
12. params[:purchase][:note] (on line 2, after the assignment)

13. params (on line 3, before the assignment)
14. params[:purchase] (on line 3, before the assignment)
15. params[:purchase][:product_id] (on line 3, before the assignment)
16. params (on line 3, after the assignment)
17. params[:purchase] (on line 3, after the assignment)
18. params[:purchase][:product_id] (on line 3, after the assignment)
19. params[:purchase][:product_id].blank? (on line 3, after the assignment)

重要提示:无论何时您调用 params,您都在访问不同的方法,并且每次您访问散列上的索引时,您都是在该散列上调用一个方法来访问所需的索引。

关于您是否应该关心:ABC 大小是衡量代码质量的标准,因此通常最好坚持使用它,当然,只要它有意义。

但是有一些方法可以重构代码以降低 ABC 的复杂性。一项建议如下:

def sanitize_params
  params.tap do |params|
    params[:purchase][:invoice] = nil if params.dig(:purchase, :invoice) == ''
    params[:purchase][:note] = nil if params.dig(:purchase, :note) == ''
    params[:purchase][:product_id] = nil if params.dig(:purchase, :product_id).blank?
  end
end

在这个例子中,Branch 的复杂度降低了很多,因为我们只调用外部 params 一次并应用 tap 块内的所有更改。此外,通过在参数上使用 dig 方法,我们只调用一种方法来达到我们想要的深度。

另一个想法是将此方法分解为更具体的方法来清理每个属性,例如。

希望对您有所帮助。