Why do I need to run my sinatra app again when making changes and my environment is not :development? - ruby

I just implemented Compass configuration for my Sinatra app but when I change the environment to :test or :production and modify my files like screen.sass or index.haml my changes are not reflected when I reload the page so I need to run my app again?
Is it normal? Is is just me?
This is how my app.rb file looks like:
require 'sinatra'
require 'haml'
require 'sass'
require 'compass'
require './helpers.rb'
configure do
set :environment, :test
Compass.configuration do |config|
settings.environment == :production ?
config.output_style = :compressed :
config.output_style = :nested
settings.environment == :development ?
config.line_comments = true :
config.line_comments = false
end
set :sass, Compass.sass_engine_options
end
before do
#js = 'javascript:;'
end
get '/scripts/jquery.js' do
# Downloads the latest jQuery 1.x version when needed. Requires to reload the page after done.
`curl "https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" >> public/scripts/jquery.js`
end
get '/styles/:name.css' do
sass :"styles/#{params[:name]}"
end
get '/?' do
haml :index
end
get '/:page/?' do
haml params[:page].to_sym
end
Any idea?

Generally, if you make a change to a running Sinatra application, you have to restart the application, as the program has already been loaded to memory.
There are options for automatically detecting changes and restarting the application on the Sinatra FAQ.

Since Shotgun fix the issue partially (reloading the files for your at production, maybe try with Sinatra::Reloader which, IMHO, works better than Shotgun.
Maybe something like (not tested)
require "sinatra"
configure(:production) do |c|
require "sinatra/reloader"
c.also_reload "*.sass", "*.haml"
end
That being said, are you sure you do need this kind of behavior on a production/test environment for updating? Development env. should be (at least, for what I use it for) for this kind of hot testing.

I used to use sinatra::reloader
but I didn't like the huge dependencies incurred (as should we all be mindful how many gems get activated)
pistol ( at a tender age of ver 0.0.2) and I think does the required job nicely

I use shotgum gem for this.
gem install shotgun
then
shotgun app.rb
from within the app dir
this then reloads the app per request, rather than holding the whole thing in memory. you access the site on localhost:9393

Related

Sinatra Routing - Separate Files

I'm going through a recently released book on Sinatra that demonstrates this way of setting up routes in different files:
# app.rb
require "sinatra"
require "slim"
class Todo < Sinatra::Base
# ...
Dir[File.join(File.dirname(__FILE__), "lib", "*.rb")].each { |lib| require lib }
end
# lib/routes.rb
get "/test" do
"The application is running"
end
# config.ru
require "sinatra"
require "bundler/setup"
Bundler.require
ENV["RACK_ENV"] = "development"
require File.join(File.dirname(__FILE__), "app.rb")
Todo.start!
However, it fails to find the route at http://localhost:4567/test. It would make sense to me that this should work when I run ruby config.ru or bundle exec rackup -p 4567. But coming from Rails development where all this configuration is built-in, I don't have a complete understanding of how everything gets wired together. The server is running on that port and I get the Sinatra doesn't know this ditty 404 page. If I reopen the class as suggested by this SO answer, the /test route is found.
# lib/routes.rb
class Todo < Sinatra::Base
get "/test" do
"The application is running"
end
end
Is there something I'm missing about this suggested way to include routes without reopening the class?
Try ruby app.rb, it should work.
You'll need to restart the webserver to load routes that were added while it was running. Routes are loaded into memory when app.rb is invoked and Sinatra is launched. The route itself looks fine and it appears routes.rb is being imported successfully via Dir[File.join(File.dirname(__FILE__), "lib", "*.rb")].each { |lib| require lib }.
If you're running the server directly through terminal Ctrl+X, Ctrl+C should shut it down, then restart it via rackup config.ru* or ruby app.rb. You may confirm the route is recognized by making a get request through your browser to: http://127.0.0.1:4567/test.
For the rackup config.ru command to work, you can change config.ru to something like:
# config.ru
require './app'
run Sinatra::Application
This is just a deployment convenience.
Edit: #shaun, because Todo extends Sinatra::Base it's fine to use run Todo in your case.
The book suggested Todo.start! to run the application from the config.ru file, but the Sinatra documentation example uses run Sinatra::Application. So I just changed the line from Todo.start! to
run Todo
That seems to work, but I'll have to look into the consequences.

Sinatra exits without error

I'm very new to Sinatra, and I'm trying to get asset management & compiling working according to this article. Here is my main file so far:
require 'sinatra/base'
require 'sinatra/assetpack'
require 'sass'
class App < Sinatra::Base
register Sinatra::AssetPack
assets do
css :application, [
'/css/main.scss'
]
css_compression :sass
end
get '/hi' do
erb "Hello World!"
end
end
but, for some reason, when I run ruby main.rb, it just exits without failure or anything. Is there a special keyword to get the application to serve files?
Using the modular style of Sinatra application, as you are doing, running ruby main.rb is going to exit without error because it is being treated as a standard ruby application and no webserver is ever created.
You have two options.
1 Add run! if app_file == $0 just before the final end statement in your example.
This will allow you to run the app with ruby main.rb
2 (This is the preferred method) Create a rackup file config.ru with the following contents.
require './main.rb'
run App
Now you can serve the application with the command rackup -p 4567 where 4567 is whatever port number you want to use.
You need to start the application
require 'sinatra/base'
require 'sinatra/assetpack'
require 'sass'
class App < Sinatra::Base
register Sinatra::AssetPack
assets do
css :application, [
'/css/main.scss'
]
css_compression :sass
end
get '/hi' do
erb "Hello World!"
end
run! if app_file == $0
end
one observation, erb should point to a template, example:
get '/hi' do
erb :home
end
should look for a file in ../views/home.erb
Also Assuming you already did gem install sinatra. I would also use the rerun gem while developing in sinatra, gem install rerun then rerun ruby app.rb. Rerun will reload your project when you make changes to your code so you won't have to restart the app when ever you make a change.

Why is my Sinatra app showing a blank screen?

My Sinatra app was working on my local server a few days ago, but now it simply isn't running, and all I get is a blank screen. Even when I deploy to Heroku, nothing works.
Here's a GitHub repository where you can check out my code: https://github.com/aayalur/Sinfoursq
I think the problem is with my config.ru file.
# Gemfile
#require "rubygems"
#require "bundler/setup"
#require "sinatra"
require "./main"
set :run, false
set :raise_errors, true
run Sinatra::Application
Thanks!
You app doesn't display anything because you haven't closed a script tag. You would have noticed that if you inspected the DOM.
By the way, you start your app twice: once in main.rb, and then in config.ru.
You can notice that when Ctrl+C'ing the app: it starts again and you gotta shut it down a second time.
Since your app needs to be run on Rack, get rid of the Sinatra.run! if __FILE__ == $0 and start it with rackup, as explained in Sinatra's documentation.
This will fix the problems related to running the app.
In your config.ru leave this way:
require "rubygems"
require "bundler"
Bundler.require
require "./app"
run Sinatra::Application

With Ruby + Webrick + Sinatra, where does 'development?' method come from?

Where does the concept of 'development mode' come from when using ruby + webrick + sinatra?
require 'sinatra'
require 'sinatra/reloader'
get '/test' do
development?.to_s
end
When I run the above app by 'ruby test.rb -p 3000' http://localhost:3000/test returns "true" ... but why does it return true? Is development mode a ruby, webrick, rack or sinatra concept? Also, is this functionality documented anywhere in particular in a non-rails specific manner? I'm finding many people reference the concept of development mode, but I've been surprised by how hard it has been to find relevant information ... maybe I'm just not google-ing the right keywords ...
Sinatra's source code (base.rb) shows these 3 definitions:
def development?; environment == :development end
def production?; environment == :production end
def test?; environment == :test end
So those true/false methods are based on the set environment. Sinatra defaults to run in development mode unless you tell it otherwise (when you start a Sinatra app, you'll see something like
== Sinatra/1.2.6 has taken the stage on 4567 for **development** with backup from WEBrick".
To tell it to run in production, you would do this:
ruby test.rb -p 3000 -e production

Reloading Sinatra app on every request on Windows

I've set up Rack::Reload according to this thread
# config.ru
require 'rubygems'
require 'sinatra'
set :environment, :development
require 'app'
run Sinatra::Application
# app.rb
class Sinatra::Reloader < Rack::Reloader
def safe_load(file, mtime, stderr = $stderr)
if file == Sinatra::Application.app_file
::Sinatra::Application.reset!
stderr.puts "#{self.class}: reseting routes"
end
super
end
end
configure(:development) { use Sinatra::Reloader }
get '/' do
'foo'
end
Running with thin via thin start -R config.ru, but it only reloads newly added routes. When I change already existing route, it still runs the old code.
When I add new route, it correctly reloads it, so it is accessible, but it doesn't reload anything else.
For example, if I changed routes to
get '/' do
'bar'
end
get '/foo' do
'baz'
end
Than / would still serve foo, even though it has changed, but /foo would correctly reload and serve baz.
Is this normal behavior, or am I missing something? I'd expect whole source file to be reloaded. The only way around I can think of right now is restarting whole webserver when filesystem changes.
I'm running on Windows Vista x64, so I can't use shotgun because of fork().
You could try sinatra-reloader, which is known to work well on Windows (also, it's faster than shotgun).
This works:
# config.ru
require 'rubygems'
require 'app'
set :environment, :development
run Sinatra::Application
# app.rb
require 'sinatra'
class Sinatra::Reloader < Rack::Reloader
def safe_load(file, mtime, stderr = $stderr)
if file == File.expand_path(Sinatra::Application.app_file)
::Sinatra::Application.reset!
stderr.puts "#{self.class}: reseting routes"
end
super
end
end
configure(:development) { use Sinatra::Reloader }
get '/' do
'foo'
end
It matters from where you have the require statement. But I find the following solution more elegant and robust:
# config.ru
require 'rubygems'
require 'sinatra'
require 'rack/reloader'
require 'app'
set :environment, :development
use Rack::Reloader, 0 if development?
run Sinatra::Application
# app.rb
Sinatra::Application.reset!
get '/' do
'foo'
end
Does Shotgun not work on Windows?
From the README:
Shotgun
This is an automatic reloading version of the rackup command that's shipped with
Rack. It can be used as an alternative to the complex reloading logic provided
by web frameworks or in environments that don't support application reloading.
The shotgun command starts one of Rack's supported servers (e.g., mongrel, thin,
webrick) and listens for requests but does not load any part of the actual
application. Each time a request is received, it forks, loads the application in
the child process, processes the request, and exits the child process. The
result is clean, application-wide reloading of all source files and templates on
each request.
You can also try using Trinidad a JRuby Rack container based on Tomcat. In my experience it does change reloading by default without having to modify your source files. Bloody fast too. Obviously no good if you are using native libraries, but if you are deploying on Windows you are probably used to adopting a pure-ruby approach.
Its syntax is just as simple as the thin approach:
jruby -S trinidad -r config.ru
There is no Java specific yak shaving (i.e. creating web.xml or WARing up your Ruby app) and the gem is simple to install.

Resources