Rails 方法参数调用约定问题

问题描述 投票:0回答:1

我有以下带有很多参数的方法。我已将此方法从参数列表转换为哈希,以避免与默认参数混淆。

 def foo_bar(options = {})
    Rails.logger.info("Got params #{options.inspect}")

    good_name = options[:foo1]
    another_param = options[:foo2]
    yet_another = options[:foo3] || "yes"
    still_one = options[:foo3]
    valid_name = options[:foo4]
    easy_name = options[:foo5]
    mode = options[:foo6]
..

现在调用这个方法很容易,只使用上下文中必需的参数,这很好

    foo_bar(foo1: my_foo1, foo3: my_foo3, foo6: my_mode)

但我的问题是,由于 Rails 通常是非常直观的语言,你有很多快捷方式和方法来做事情,如何使这个方法参数签名更清晰

  • 我不必从哈希中提取参数,它们会自动分配给相应的本地变量,而无需那些“额外”行,这些行现在从选项哈希中进行分配。
  • 没有一长串带有默认值的参数

想要避免这种情况,因为在调用此方法时无法自由选择我想要为其赋值的参数。另外,调用也不清楚哪个参数是哪个参数,因为它们不是按名称引用,而是按值和顺序引用。

def foo_bar(good_name, another_param = nil, yet_another = "yes", still_one = "xx", valid_name = nil, easy_name = nil, foo6 = "std")

方法重载在这里不起作用,也尝试过。这不像 C# 或 Java 那样实现。

我尝试过: 方法重载 参数作为哈希值 参数“正常方式”

ruby-on-rails methods parameters
1个回答
0
投票

首先,声明该方法的现代方法是使用关键字参数而不是哈希作为位置参数。

def foo_bar(**options)
  # ...
end

位置参数方法的问题之一是,您实际上可以传递不是哈希的输入,它会在方法内部爆炸,而不是得到一个参数错误,这会立即告诉您出了什么问题。

**
是一个双标,意味着我们正在吞噬传递给该方法的任何关键字参数。

处理默认值的方法有很多种。如果您不想在方法定义中显式列出它们,您可以使用一个私有方法来生成默认选项:

class Foo
  def bar(**kwargs)
    options = kwargs.reverse_merge(default_options)
    # ...
  end

  private

  def default_options
    { 
      a: 1,
      b: 2
    }
  end
end

这让子类可以重写该方法,并且在 Rails 代码库中随处可见。

reverse_merge
来自 ActiveSupport,您可以在普通 Ruby 中使用
merge
执行相同的操作,但顺序相反。

我不必从哈希中提取参数,它们会自动分配给相应的本地变量

这种模式通常称为批量分配:

class Thing
  attr_accessor :foo
  attr_accessor :bar

  def initialize(**attributes)
    attributes.each do |key, value|
      send("#{key}=", value)
    end 
  end 
end 

Thing.new(foo: "a", bar: "b")

对于传递给方法的每个关键字参数,我们尝试调用与键同名的 setter 方法。虽然您可以直接调用

instance_variable_set
并设置 Ivars,但这不允许您控制可以分配的内容和方式。

在 Rails 中,您可以从 ActiveModel::AttributeAssignment 在模型中免费获得此功能,并且如果需要,可以将其混合到任何类中。

© www.soinside.com 2019 - 2024. All rights reserved.