【问题标题】:Rails - redirect to current url without one of the GET paramsRails - 在没有 GET 参数之一的情况下重定向到当前 url
【发布时间】:2012-11-07 19:26:56
【问题描述】:

我在 Rails 应用程序中有一个非常简单的问题,但我找不到优雅的解决方案。

我有一个类似的网址: http://www.example.com/some-path/?foo=123&baz=456

我想处理其中一个参数并重定向到: http://www.example.com/some-path/?baz=456

我希望这通常适用于任何带有参数“foo”的 URL,所以我不想在重写代码中指定“baz”。

我想要的是这样的:

redirect_to request.path, :params => request.query_parameters.except(:foo)

除非那不太行。我知道我可以手动正则表达式或解析查询字符串,但我认为有更好的方法。

【问题讨论】:

  • 在什么情况下不起作用?你有错误吗?你得到一个你没想到的 URL 吗?
  • 上面的代码实际上并没有在重定向中保留 baz=456
  • 作为参考,这段代码完全符合我的要求(为格式化道歉):query_string = request.query_parameters.except(:foo).map{|k,v| "#{k}=#{v}"}.join('&')redirect_to query_string ? "#{request.path}?#{query_string}" : request.path
  • 您评论中的代码有多个问题。重建 url 时,您并没有转义那些查询字符串参数。如果其中任何一个包含 = 或 & 或其他应编码的特殊字符,您将得到一个非常损坏的重定向 url。此外,此代码将无法正确处理 request.query_parameters 为您提供的 x[a]=1&x[b]=2 等查询参数的自动散列和数组化。这就是为什么编写自己的查询字符串操作代码通常是一个坏主意的两个原因,尤其是在像 rails 这样的复杂框架中。

标签: ruby-on-rails


【解决方案1】:

到目前为止我发现的最好的方法是使用:

url_for(params.except(:obsolete_param_name))

更新

正如grosser 所提到的,这会在您的应用程序中打开一个安全漏洞,因为攻击者可以将主机作为 url 参数传递并将用户重定向到不同的网站。为了防止这种情况,您可以使用rap1ds 的建议并指定只需要使用路径。

为此,您可以使用类似这样的辅助函数:

def secure_path_for(params, *excluded_params)
  url_for(params.except(*excluded_params).merge(only_path: true))
end

【讨论】:

  • 这是一个安全漏洞,它会将人们重定向到给定的主机 ?host=attacker.com -> attack.com
  • 你是对的!因此,也许另一种解决方案是将其包装在另一种方法中,这将确保不会修改诸如“主机”之类的键(类似于强参数为防止大规模分配所做的事情)。
  • url_for 有一个选项only_path,所以如果你不需要绝对URL,你可以做url_for(params.except(:obsolete_param_name).merge(only_path: true) 这应该不会暴露任何安全问题,不是吗?至少我想不出。
  • 我必须修改一个参数去当前路线,我使用:url_for(params.merge({my_param: new_value}))
  • url_for(params.except(:obsolete_param_name, :host)) 呢?
【解决方案2】:

在传递它之前删除 params[:foo] 怎么样。可能是这样的:

params.delete[:foo]
redirect_to request.path, :params => params

它不是很优雅,但它只增加了一行。顺便说一下,Params 是一个辅助方法,可以获取 url 的当前参数

【讨论】:

  • 假设 /some-path/ 的现有控制器可以处理两种形式的预期 URL(例如 if params[:foo]...),那么这是一个非常合适的解决方案。您可以创建一个与 foo-less 路径匹配的命名路由,但这会使事情变得不那么明显,恕我直言。
  • 这基本上等同于我上面所做的(不起作用),除了 params 还从路由中拉入 params,所以你可能会在 URL 中得到你不想要的额外内容。
  • 是的,没错。这假设唯一的目标是删除参数 :foo 进入重定向。
【解决方案3】:

在 Rails 5 中,如果您尝试这样做,您将收到 non-sanitized request parameters 错误url_for(params.except(:param))

所以我找到了这种方法:

request_url = request.url # eg. http://qwe.com/path?param1=1&param2=2

query_hash = Rack::Utils.parse_query(URI.parse(request_url).query).except('param1')
url = query_hash.empty? ? request.path : "#{request.path}?#{query_hash.to_query}"

puts url #=> /path?my_param2=2

redirect_to url

【讨论】:

    【解决方案4】:
    uri = URI.parse(request.url)
    new_query = uri.query.split("&").reject{|pair|
      k,v = pair.split("=")
      k =~ /^foo\[?/ # reject params named "foo" or "foo[anything"
    }.join("&")
    # if the new querystring is empty, assign nil instead of "" so we don't
    # end up with a solitary question mark at the end of the url.
    uri.query = (new_query.empty? ? nil : new_query)
    redirect_to uri.to_s
    

    在尝试以“Rails 方式”做事时遇到一些不明显的问题后,我来到了上述解决方案,如果有这样的方式来解决这个问题。例如:

    • Rails 参数解析将自动为使用特殊方括号语法的查询参数实例化数组和散列:?x[a]=1&y[]=2 变为 {"x"=>{"a"=>"1"}, "y"=>["2"]} 等等,因此使用提供的查询字符串和参数例程的代码很难处理对此。因此,通过原始字符串值过滤参数可能很困难。即使是非 rails/rack CGI 模块也会为您提供数组而不是参数值的字符串。
    • rails params 散列包括 GET、POST 和路由参数,例如 :action:controller,因此无论如何您都不能只是重复使用它来重构查询字符串。
    • 因此,像 url_for 这样的 URL 助手并没有多大帮助。

    鉴于这些问题,我发现我无法使用提供的框架功能来获得一个纯粹且不受干扰的查询字符串,从当前请求中按原样复制,这只是简单地且仅删除了一个参数。不过,上面的代码似乎运行良好。

    【讨论】:

      猜你喜欢
      • 2011-06-24
      • 1970-01-01
      • 2020-05-07
      • 1970-01-01
      • 2019-10-15
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多