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()
经过大量调试,我发现了一个问题,但我无法解释。这是一些 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()