Неверный URI Ошибка в пост-запросе Синатры

Я работаю над демонстрационным приложением Sinatra в рамках учебного курса по RSpec ( официальное репо). Приложение использует установку ActiveRecord по меню - без Rails. Когда я пытаюсь опубликовать объект Book на сервере при запуске спецификации, я получаю InvalidURIError.

Failures:

  1) App creates a book
     Failure/Error: post :books, book: { name: "My first book" }
     URI::InvalidURIError:
       bad URI(is not URI?): books
     # /Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/rack-test-0.6.3/lib/rack/test.rb:193:in `env_for'
     # /Users/andrekibbe/.rvm/gems/ruby-2.2.1/gems/rack-test-0.6.3/lib/rack/test.rb:66:in `post'
     # ./spec/rack_spec.rb:10:in `block (2 levels) in <top (required)>'

rack_spec.rb:

require "environment"
require "rack_app"

fdescribe App do
  include Rack::Test::Methods

  let(:app) { App }

  it "creates a book" do
    post :books, book: { name: "My first book" }

    expect(last_response.status).to eq 201
  end
end

rack_app.rb:

class App < Sinatra::Base
  post '/books' do
    book = Book.new params[:book]
    if book.save
      status 201
    else
      status 502
    end
  end
end

spec_helper.rb:

require "environment"
require "factory_girl"
require "database_cleaner"
require "rack/test"
require_relative "./factories.rb"

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
  config.include Rack::Test::Methods

  config.before(:suite) do
    begin
      DatabaseCleaner.start
    ensure
      DatabaseCleaner.clean
    end
  end
end

book.rb:

class Book < ActiveRecord::Base
  validates_presence_of :name
end

environment.rb:

require "sinatra"
require "active_record"

ActiveRecord::Base.establish_connection(
  adapter: :sqlite3,
  database: File.expand_path("../../db/test.sqlite3", __FILE__)
)

О чем это post :books, book: { name: "My first book" } что заставляет Rack рассматривать запрос как плохой URI?

1 ответ

Решение

Ваш код работает для меня, если вы вносите изменения, которые я рекомендовал в комментарии, однако, если вы буквально использовали следующее в своем коде:

post '/books', book: {...}

или же:

post :'/books', ...

... тогда, конечно, эти строки не будут работать. ... означает "так же, как ваш исходный код, потому что это напрасная трата моего времени, чтобы напечатать это". Вот как должно выглядеть рекомендуемое изменение:

rack_app.rb:

require "environment"
require "rack_app"

fdescribe App do
  let(:app) { App }

  it "creates a book" do
    post '/books', book: { name: "My brand new book" }
    expect(last_response.status).to eq 201
  end
end

Единственный маршрут, который определил ваше приложение, находится здесь:

class App < Sinatra::Base
  #       +--------This is the only url your App responds to  
  #       |        and ONLY if it is contained in a post request
  #       V
  post '/books' do

    book = Book.new params[:book]

    if book.save
      status 201
    else
      status 502
    end

  end

end

Даже использование символа в качестве URL не работает:

  it "creates a book" do
    post :'/books', book: { name: "My brand new book" }

И поскольку Symbol не будет работать для URL в вашем тесте rspec, это означает, что Sinatra принимает первый аргумент, данный для post(), например :'/books'и сравнивает его с маршрутами, которые вы определили в своем классе приложения:

defined_route = '/books'
requested_route = :'/books'

if requested_route != defined_route
  puts "URI ERROR"
end

--output:--
URI ERROR
Другие вопросы по тегам