Sinatra 中 params hash 的奇怪行为

Weird behavior of params hash in Sinatra

经过大量调试,我发现了一个问题,但我无法解释。这是一些 Sinatra 代码:

post '/modify' do

# at this point params contains the action key as I expect it.

  puts "1: action is #{params["action"]}"
  if (params["action"] == "del")
    puts "#{params}" 
    puts "delete"
  end

# At this point params still contains the "action" key as I expect it
  puts "2: action is #{params["action"]}"
  if (params["action"] == 'create') 
    puts "#{params}" 
    puts "create"

#### THE NEXT LINE IS THE PROBLEM!
    params = { :n => @number }
    redirect '/'
  end

# At this point params is nil
  puts "3: ????? #{params}"
  foo = params["action"]
  #puts "3: action is #{params["action"]}"
  if (foo == "refresh")
    puts "***: #{params}"
    redirect '/'
  end
  puts "3: #{params}"
  puts "3: action is #{params["action"]}"
end

当 params["action"] 不等于 del 或 create 时,此代码将给出一个错误,即 [] 在 nil 值上无效。

我得出结论,通过在未执行的条件中为参数赋值,参数哈希(实际上是 Sinatra 的一种方法)变为零。

即使 Ruby 中的变量范围无法将 if/then 识别为新范围,该行仍然不会执行。

你能看到吗?

我认为您需要温习一下“Why is HTTP protocol called stateless protocol?”中 HTML 的无国籍性质。

您正在访问的 params 变量是根据入站请求的查询参数构建的。当您执行重定向时,您将转到一个新的 URL,并且您必须将查询参数构建到 URL 中。这样,在重定向的另一侧,它可以重建为您期望的 params 哈希。有关详细信息,请参阅 Sinatra 的“Getting Started”中的 "Browser Redirect"。

将重定向想象成您即将攀登的巨墙。如果你想在到达墙的另一边时在墙的另一边拥有你当前拥有的东西,那么你必须在爬墙时随身携带它。

您似乎混淆了局部变量 params 的方法 params

让我们看一个简化的例子:

def params
  {"action" => "some-action"}
end

# the line below refers to the method #params
p params # {"action" => "some-action"}

# the variable params is created, but not assigned
params = {n: 1} if false

# any further reference to params will use the variable
p params # nil

如果您现在有问题 "why is the variable created?",简单的答案是:因为 documentation 是这么说的。

The local variable is created when the parser encounters the assignment, not when the assignment occurs:

a = 0 if false # does not assign to a

p local_variables # prints [:a]

p a # prints nil

要解决您的问题,请使用 #params= setter(假设有一个)或将方法结果检索到一个变量开始,这样所有对 params 的引用引用变量。

# assign using the setter method
self.params = { :n => @number }

# extract the contents to a variable at the start
# of the `post '/modify' do` block
params = self.params # or params()