为什么在 Rails 回调上使用大括号?

Why Curly Braces on Rails Callback?

我在 Rails 上学习 Ruby 并且在处理概念时我也在处理语法,这在您开始 RoR 时有点奇怪。根据 Michael Hartl 的教程

When hashes are the last argument in a function call, the curly braces are optional

我明白了,但是作者在提到回调时,出现了这行代码:

before_save { self.email = email.downcase }

我理解before_save是方法。谁能帮我解释一下这个论点,为什么你不能把花括号去掉?

您所指的作为参数传递的花括号是一个块。
传递给回调的块通过 instance_eval 执行,因此它的范围是记录本身。

您的代码中没有哈希。你看到的是一个块,它是一种匿名函数。 Ruby 有两种不同的块语法。此代码:

before_save { self.email = email.downcase }

...等同于此代码:

before_save do
  self.email = email.downcase
end

一般来说,大括号用于单行,do ... end用于多行。无论哪种情况,您所做的都是定义 "block" 代码,然后将其作为参数传递给 before_save 方法。这允许 Rails 将该代码块存储在变量中并稍后执行,或者将代码传递给其他方法。以上两个例子在很大程度上等同于:

my_block = proc do
  self.email = email.downcase
end

before_save(&my_block)

块参数很特殊。一个方法只能有一个块参数,而且它必须是最后一个参数。在最后一段代码中,我使用 procProc.new 的快捷方式)实际上将块保存到一个变量,然后将该变量作为一个变量传递给 before_save争论。 & 告诉 Ruby 它应该将该 Proc 视为 before_save.

的块参数

不过,有些语法问题会随着块出现。例如,这是有效的:

[ "two", "three" ].reduce "one" do |memo, item|
  memo << item
end
# => "onetwothree"

但这不是:

[ "two", "three" ].reduce "one" {|memo, item| memo << item }
# => SyntaxError: unexpected '{', expecting end-of-input

当你使用大括号语法并有参数时(如上面的"one"),你必须使用括号:

[ "two", "three" ].reduce("one") {|memo, item| memo << item }
# => "onetwothree"

除了块和 Proc 之外,Ruby 还有一种特殊的 Proc,称为 lambda。您会在某些 Rails 文档中看到 lambda,它们看起来像这样:

scope :published, -> { where(published: true) }

这是一个快捷方式:

scope :published, lambda { where(published: true) }
# ...or...
scope :published, lambda do
  where(published: true)
end

...这些都等同于:

my_lambda = ->{ where(published: true) }
scope :published, my_lambda

请注意,第二行的 my_lambda 之前没有 &。那是因为 Rails' 开发人员选择让 scope 将 lambda 作为常规参数——而不是它的块参数——我认为这主要是因为它不必是最后一个参数。

块、过程和 lambda 之间的区别超出了本答案的范围,有时甚至很微妙,但掌握这些知识是很好的知识。我推荐这篇文章以获取更多信息:https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/18-blocks/lessons/64-blocks-procs-lambdas