I am perplexed by something that isn't actually a practical problem - just a conceptual conundrum - about deploying a Sinatra app on Heroku.
I have two apps, identical in just about every respect, except that one puts most of its logic in a file that does not contain the Sinatra::Base class and uses a 'require otherfilename' to pick up the logic it needs. That Sinatra:Base class is named Kincalc.
For the app with all the logic in one file (that is, the same file that contains the Sinatra:Base class), in my config.ru file, the last line reads "run Sinatra::Application" and it launches fine. But in the other app, if I include that as the last line, the app uploads properly and says it was "deployed to Heroku" but it brings up a "Not found" message. When I have the last line read 'run Kincalc', it loads fine.
I have checked this back and forth and there is nothing different about how these two apps are built, except for the fact that one uses a second file for the logic (which is also at root). Why should this be a problem, or is this really the problem? When I try to put the second file (the one without the Sinatra class) in a separate lib folder, it still works when I call the class name but not when I call "Sinatra::Application."
Code at top level will be delegated to Sinatra::Application
, so this would be a scenario for running a classic application:
# app.rb
require 'sinatra'
get '/' do
'hi'
end
# config.ru
require './app'
run Sinatra::Application
If you define a modular app, you would run it like this:
# app.rb
require 'sinatra/base'
class Kincalc < Sinatra::Base
get '/' do
'hi'
end
end
# config.ru
require './app'
run Kincalc
Now I assume what you are trying to do is this:
# otherfilename.rb
require 'sinatra'
get '/' do
'hi'
end
# app.rb
require 'sinatra/base'
class Kincalc < Sinatra::Base
require './otherfilename'
end
# config.ru
require './app'
run Kincalc # Sinatra::Application seems to work
The behavior you experience (getting a 404 File Not Found) is actually correct, as require
does not care about the lexical scope it is called in. Check out the following example
# a.rb
puts "in a, top level: #{self.inspect}"
module Example
puts "in a, nested: #{self.inspect}"
require 'b'
end
# b.rb
puts "in b: #{self.inspect}"
The resulting output should be:
in a, top level: main
in a, nested: Example
in b: main
So, if you want to use one modular application, you should do something like this:
# otherfilename.rb
Kincalc.get '/' do
'hi'
end
Or open the class again:
# otherfilename.rb
class Kincalc
get '/' do
'hi'
end
end
Or you could actually have otherfilename.rb
make it's definitions on Sinatra::Application
and utilize that in Kincalc
.
# app.rb
require 'sinatra/base'
require './otherfilename'
class Kincalc < Sinatra::Base
use Sinatra::Application
end
Or you could change where top level DSL methods are delegated to:
# app.rb
require 'sinatra/base'
class Kincalc < Sinatra::Base
Sinatra::Delegator.target = self
require './otherfilename'
end