Ruby on rails Rspec:在路由规范中添加一些头请求

Ruby on rails Rspec:在路由规范中添加一些头请求,ruby-on-rails,rspec,rspec-rails,Ruby On Rails,Rspec,Rspec Rails,我正在开发一个Rails应用程序,该应用程序有一个JSON格式的RESTAPI,并进行了版本控制(根据Ryan出色的cast:) 例如,有一个等级库/请求等级库: require 'spec_helper' describe "My Friends" do describe "GET /my/friends.json" do it "should get my_friends_path" do get v1_my_friends_path, {}, {'HTTP_ACC

我正在开发一个Rails应用程序,该应用程序有一个JSON格式的RESTAPI,并进行了版本控制(根据Ryan出色的cast:)

例如,有一个等级库/请求等级库:

require 'spec_helper'

describe "My Friends" do
  describe "GET /my/friends.json" do
    it "should get my_friends_path" do
      get v1_my_friends_path, {}, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}
      response.status.should be(401)
    end
  end
end
而且效果很好。但是(保留此示例)我们如何编写路由规范?例如,此规范不正确:

require 'spec_helper'

describe "friends routing" do
  it "routes to #index" do
    get("/my/friends.json", nil, {'HTTP_ACCEPT' => 'application/vnd.myapp+json; level=1'}).
      should route_to({ action: "index",
                    controller: "api/v1/private/my/friends",
                        format: "json" })
  end
end
我尝试了不同的方法(例如
request.headers['Accept']
@request.headers['Accept']
,其中
request
未定义,
@request
为零);我真的不知道该怎么办


我使用的是Ruby 1.9.3、Rails 3.2.6和rspec Rails 2.11.0。谢谢。

由于
actionpack-3.2.5/lib/action\u dispatch/Routing/route\u set.rb
中的
第608行
,当前无法发送路由规范中的附加标头,其中说明:

env = Rack::MockRequest.env_for(path, {:method => method})
path
是您请求的路径
“/my/friends.json”
,方法是
:get
生成的
env
包含如下内容:

{
 "rack.version"=>[1, 1],
 "rack.input"=>#<StringIO:0xb908f5c>,
 "rack.errors"=>#<StringIO:0xb908fac>,
 "rack.multithread"=>true,
 "rack.multiprocess"=>true,
 "rack.run_once"=>false,
 "REQUEST_METHOD"=>"GET",
 "SERVER_NAME"=>"your-url.com", # if path was http://your-url.com/
 "SERVER_PORT"=>"80",
 "QUERY_STRING"=>"",
 "PATH_INFO"=>"/",
 "rack.url_scheme"=>"http",
 "HTTPS"=>"off",
 "SCRIPT_NAME"=>"",
 "CONTENT_LENGTH"=>"0"
}
让我们知道,如果你能够模仿环境,让它返回你的标题,将很高兴知道

问候
克里斯托夫

结合克里斯托弗和皮奥特的答案,我想出了一个适合我的解决方案。我正在使用rspec和rails 3.0

it 'should route like i want it to' do 
  Rack::MockRequest::DEFAULT_ENV["HTTP_ACCEPT"] = "*/*"
  {get: "/foo/bar"}.
    should route_to(
    controller: 'foo',
    action: 'bar',
  )
  Rack::MockRequest::DEFAULT_ENV.delete "HTTP_ACCEPT"
end

您可以使用rspec的
和_wrap_original
来模拟
Rack::MockRequest.env_for
方法:

expect(Rack::MockRequest).to receive(:env_for).and_wrap_original do |original_method, *args, &block|
  original_method.call(*args, &block).tap { |hash| hash['HTTP_ACCEPT'] = 'application/vnd.myapp+json; level=1' }
end

对于Rails 3和Rails 4,我在

由于
Rack>=2.0.3
(),因此
Rack::MockRequest::DEFAULT_ENV

您可以重新定义该常数,并使用它来消除Ruby警告:

around do |example|
  silence_warnings do
    Rack::MockRequest::DEFAULT_ENV = Rack::MockRequest::DEFAULT_ENV.dup
  end

  Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1'

  example.run

  Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT'
end

这是一个小技巧,但它很有魅力。

@justNeph你能详细介绍一下你是如何实现它的,或者你的规范是什么样子的吗?你是如何克服“不能修改冻结哈希”错误的?@ChrisHough你可以对它进行dum并返回新的哈希:@ChrisHough Hash=original\u方法。call(*args,&block)。dup我把它放在哪里?在设计配置中?你是如何通过“无法修改冻结哈希”错误的?@ChrisHough-Hmm,我不记得有过那个错误。但是请注意,这个解决方案是针对Rails3的。你可能在4.x上,他们可能从那时起就开始冻结默认的_ENV散列…是的,我不得不放弃我的路由规范以获得请求规范。这对我来说很好。你是如何通过“无法修改冻结的哈希”错误的?你是如何通过“无法修改冻结的哈希”错误的?我可能使用的是旧版本的rspec或ruby,其中哈希没有被冻结。
expect(Rack::MockRequest).to receive(:env_for).and_wrap_original do |original_method, *args, &block|
  original_method.call(*args, &block).tap { |hash| hash['HTTP_ACCEPT'] = 'application/vnd.myapp+json; level=1' }
end
around do |example|
  Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1'

  example.run

  Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT'
end
around do |example|
  silence_warnings do
    Rack::MockRequest::DEFAULT_ENV = Rack::MockRequest::DEFAULT_ENV.dup
  end

  Rack::MockRequest::DEFAULT_ENV['HTTP_ACCEPT'] = 'application/vnd.vendor+json; version=1'

  example.run

  Rack::MockRequest::DEFAULT_ENV.delete 'HTTP_ACCEPT'
end