Sinatra routes not working in modular app? - ruby

I've converted a classic Sinatra application to a modular application. Now suddenly my put, patch and delete routes stopped working. get and post work fine. Is there something I need to do to get these to work in a modular app that is different from classic?
%form{action: "/addsomething", method: 'post'}
%input{type: 'hidden', name: '_method', value: 'put'}
I get a 404 now when I attempt to access one of the above mentioned routes.
require 'sinatra/base'
class MyClass < Sinatra::Base
put '/addsomething' do
'HELLO WORLD!'
end
get '/hello' do
'hello world'
end
end

The method_override setting (that allows the _method field to override the HTTP method) is false by default in modular style. You need to enable it with:
enable :method_override

You can still inherit from Sinatra::Application in the modular style to keep the default settings:
require 'sinatra/base'
class MyClass < Sinatra::Application
put '/addsomething' do
'HELLO WORLD!'
end
get '/hello' do
'hello world'
end
end

Related

Sinatra method `development?` undefined

The Sinatra docs say that development? will return true when the environment is development, but I receive an error stating that the method development? is undefined.
I tried skipping the shorthand and testing the ENV['RAKE_ENV'] variable itself, but it was just nil.
This is the error I'm getting:
undefined method `development?' for main:Object (NoMethodError)
and this is the code that is triggering the error:
require 'dm-sqlite-adapter' if development?
I am using the modular style app. The line above is an separate file that only manages the model. What's going on?
I struggled with this one, too. Here's what I discovered along the way.
You need to be "inside" a class that inherits from Sinatra::Base (such as Sinatra::Application, which inherits from Base) to be able to use the development? method, which is defined in base.rb.
In a classic Sinatra app you are already coding "inside" a class that inherits from Sinatra::Base. So development? will just work "anywhere".
In modular Sinatra the development? will only work in Sinatra::Base sub-classes, such as:
require 'sinatra/base'
# Placing
# require 'dm-sqlite-adapter' if development?
# here will not work.
class ApplicationController < Sinatra::Base
require 'dm-sqlite-adapter' if development? # But here it works
...
end
# Placing
# require 'dm-sqlite-adapter' if development?`
# AFTER the above class will still not work
class SomethingElse
# nor will `development?` work here, since it is called inside
# a class without Sinatra::Base inheritance
...
end
So basically you can use an ApplicationController class that inherits from Sinatra::Base and inside here check for development?. The same goes for sub-classes that inherits from your ApplicationController class:
class UserController < ApplicationController
require 'dotenv' if development?
...
end
For modular Sinatra, in the (main:Object) code text "outside" Sinatra::Base sub-classes, you need to follow Arup's instructions:
if Sinatra::Base.environment == :development
require 'awesome_print'
require 'dotenv'
Dotenv.load
...
end
Since you are using the modular style, you need to add the module namespace Sinatra::Base before the method.
So you will be able to access Sinatra::Base.development? anywhere in the app.

Error handlers don't run in modular Sinatra app

I have a Sinatra application that uses the modular style. Everything works fine apart from my error handler blocks which don't get invoked. Here's the relevant code:
app.rb
require_relative './routes/base'
require_relative './routes/routing'
module Example
class App < Sinatra::Application
use Routes::Base
use Routes::Routing
end
end
base.rb
require 'sinatra/base'
module Example
module Routes
class Base < Sinatra::Application
configure do
# etc.
end
# Error pages.
error 404 do # <- Doesn't get invoked.
erb :not_found
end
error 500 do # <- Doesn't get invoked.
erb :internal_server_error
end
end
end
end
routing.rb
module Example
module Routes
class Routing < Base
get '/?' do
erb :home
end
end
end
end
Why don't my error handlers work?
Thanks in advance.
The use method is for adding middleware to an app, you can’t use it to compose an app like this.
In your example you actually have three different Sinatra applications, two of which are being run as middleware. When a Sinatra app is run as middleware then any request that matches one of its routes is handled by that app, otherwise the request is passed to the next component in the Rack stack. Error handlers will only apply if the request has been handled by the same app. The app that you have defined the error handlers in has no routes defined, so all requests will be passed on down the stack — the error handlers will never be used.
One way to organise a large app like this would be to simply use the same class and reopen it in the different files. This other question has an example that might be useful: Using Sinatra for larger projects via multiple files.

Webrick does not start when starting a Sinatra app

Any idea why Webrick refuses to start?
require 'sinatra/base'
require 'slim'
class Blog < Sinatra::Base
get '/' do
slim :home
end
end
Running ruby blog.rb does nothing. No error is raised.
The built in web server isn’t started when using the modular style of Sinatra apps. See the docs for the differences between modular and classic styles.
To get it to run like a classic style app, add this line to the bottom of your Blog class:
run! if app_file == $0

Testing expectations on doubles in Sinatra app using spec

I want to verify that a method was called on a service I want to inject into a Sinatra application using rspec but I can't find an example of how this is done. Here is my spec...
RSpec.configure do |config|
config.include Rack::Test::Methods
end
def app
App
end
describe 'Login' do
context 'when the user is logged out' do
describe 'POST on /signup' do
it 'invokes signup on the user service with the correct parameters' do
service = double('user_service').as_null_object
service.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end
end
end
end
Here the App is a modular Sinatra app. I come from a .NET background and I'd use constructor injection here to solve this problem but I know this isn't the ruby way to do it.
Help, as always, is appreciated.
Assuming that you're expecting to receive the message on a new instance of UserService, there are a couple of ways to do this. If you are using a recent version of rspec, this should work:
it 'invokes signup on the user service with the correct parameters' do
UserService.any_instance.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end
Alternatively, this should work in just about any version of rspec:
it 'invokes signup on the user service with the correct parameters' do
service = double('user_service').as_null_object
UserService.stub(:new).and_return(service)
service.should_receive(:signup).with(:username => 'RobA2345')
post '/signup'
end

Authlogic Webapp does not work any more in selenium-Javascript tests

Testing a Ruby on Rails application, I have working tests (also asa logged in user), however as soon as I put the ":js=>true" option behind a test
it "does", :js => true do
activate_authlogic
visit '/'
end
a get the web page with an internal error back
You must activate the Authlogic::Session::Base.controller with a controller object before creating objects
How can I get this to work? How can I determine the error more closely?
By now it works for me, I think because of this dirty snippet
module Authlogic
module Session
module Activation
module ClassMethods
def controller
if !Thread.current[:authlogic_controller]
Thread.current[:authlogic_controller] = Authlogic::TestCase::MockController.new
end
Thread.current[:authlogic_controller]
end
end
end
end
end
witch comes from the question SO: authlogic-with-capybara-cucumber-selenium-driver-not-working

Resources