【问题标题】:Passing attributes in test url - Rspec / Addressable gem在测试 url 中传递属性 - Rspec / Addressable gem
【发布时间】:2017-10-30 13:17:05
【问题描述】:

从视图文件中,我在 url 中传递属性:

%= link_to piece_path(@current_piece, file: file, rank: rank), method: :patch do %>

这给出了像http://localhost:3030/pieces/%23?file=8&rank=8这样的网址

我需要从这个 url 中提取文件的值和排名,以更新数据库字段(移动后棋子的坐标)。

在控制器中,我正在尝试使用 Addressable gem:

def update
    (some code)
    current_piece.update_attributes(piece_params)
    (more code)
end

private

def piece_params
    uri = Addressable::URI.parse(request.original_url)
    file = uri.query_values.first    ## I don't know if "first" 
    rank = uri.query_values.last     ## and "last" methods will work
    params.require(:piece).permit({:file => file, :rank => rank})
end

当我检查 uri 我得到:#<Addressable::URI:0x3fa7f21cc01c URI:http://test.host/pieces/2> url 后面没有属性散列。因此uri.query_values 返回nil。我不知道如何在测试中反映这样的事情

错误信息:

1) PiecesController pieces#update should update the file and rank of the chess piece when moved
     Failure/Error: file = uri.query_values.first

     NoMethodError:
       undefined method `first' for nil:NilClass

在 Controller_spec 中:

describe "pieces#update" do
    it "should update the file and rank of the chess piece when moved" do
      piece = FactoryGirl.create(:piece)
      sign_in piece.user
      patch :update, params: { id: piece.id, piece: { file: 3, rank: 3}}
      piece.reload
      expect(piece.file).to eq 3
      expect(piece.rank).to eq 3
   end

我无法从 localhost 浏览器检查逻辑是否有效(我目前没有碎片对象,所以我遇到了错误)。也在努力。

我的问题是关于考试的;但是,如果有建议以不同的方式从 url 中提取属性,我会全力以赴!

【问题讨论】:

  • 您需要删除 '@current_piece' 周围的引号,因为您传递的是文字字符串 '@current_piece' - 而不是实例变量的值。
  • 好收获!实际上,我在实际视图文件中没有引号,而是从错误的文件中粘贴了它(我使用它作为占位符来躲避由于没有碎片对象而导致的路由错误,因此没有 id)
  • 我编辑了我的问题以更正此问题

标签: ruby-on-rails rspec addressable-gem


【解决方案1】:

您无需手动解析请求 URI 即可在 Rails 中获取查询参数。

Rails 构建在 Rack CGI 接口之上,该接口解析请求 URI 和请求正文,并以 params 哈希的形式提供参数。

例如,如果您有:

resources :things

class ThingsController < ApplicationController
  def index
    puts params.inspect
  end
end

请求/things?foo=1&amp;bar=2 会输出如下内容:

{
  foo: 1,
  bar: 2,
  action: "index",
  controller: "things"
}

link_to method: :patch 使用 JQuery UJS 让您使用 &lt;a&gt; 元素通过 GET 以外的其他方法发送请求。它通过附加一个创建表单并将其发送到 HREF 属性中的 URI 的 javascript 处理程序来做到这一点。

但是,与 rails 中的“正常形式”不同,参数不是嵌套的:

<%= link_to piece_path(@current_piece, file: file, rank: rank), method: :patch do %>

将给出以下参数哈希:

{
  file: 1,
  rank: 2
}

没有

{
  piece: {
    file: 1,
    rank: 2
  } 
}

如果您想要嵌套键,则必须提供以下参数:

<%= link_to piece_path(@current_piece, "piece[file]" => file, "piece[rank]" => rank), method: :patch do %>

【讨论】:

  • 您也可以使用button_to 创建离散的表单元素而不是链接。这使您可以在请求正文中而不是查询字符串中传递参数。
  • 谢谢,这帮助我了解了请求正文的工作原理。最后button_to 为我工作,我现在将发布解决方案。
【解决方案2】:

如果您的网址是http://localhost:3030/pieces/%23?file=8&amp;rank=8,您应该可以这样做:

def piece_params
    params.require(:piece).permit(:rank, :file)
end

然后通过params[:rank]params[:file] 在您的操作中访问它们 在我尝试分配值之前,我通常使用params[:file].present? 来确保参数在那里。这样的事情应该可以工作:

p = {}
if params[:rank].present?
  p[:rank] = params[:rank]
end
if params[:file].present?
  p[:file] = params[:file]
end
current_piece.update_attributes(p)

FWIW,您可能不应该使用 URL 字符串将参数传递给 PATCH/PUT 请求。您可以考虑通过表单或其他方式传递它们。

【讨论】:

  • 感谢您知道我应该能够使用更简单的 piece_params 定义来做到这一点;并且我可以以与通过 url 不同的方式传递这些参数。对于我正在研究的项目而言,安全性不是问题,但绝对值得了解!
【解决方案3】:

button_to 具有嵌套属性有效;在视图文件中:

<%= button_to piece_path(@current_piece), method: :patch, params: {piece: {file: file, rank: rank}} do %>

并在控制器中保持简单:

def piece_params
  params.require(:piece).permit(:rank, :file)
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多