I have a simple script written in Ruby that can start and stop an executable. I would like to have two buttons on a simple web page, start and stop, and execute the code on the machine the page is hosted from. What would be the easiest/lightest way of doing it?
I would suggest using Sinatra for such a small tasks. Let's start with Gemfile, if you're using bundler:
source 'https://rubygems.org'
gem 'sinatra'
gem 'slim'
Then just run "bundler install" or just install these gems manually. Let's write our tiny web server, create myapp.rb with following content:
require 'sinatra'
get '/' do
slim :index
end
post '/start' do
puts "Starting..."
redirect '/'
end
post '/stop' do
puts "Stopping..."
redirect '/'
end
This basically creates three handlers for paths "/", "/start", "/stop". "/" renders slim html template (we will get there soon), "/start" and "/stop" for now just print a text into STDOUT and redirects you back to "/". Let's create a folder "views" and file "views/index.slim" in it:
doctype html
html
head
title Simple Ruby web interface
body
form method="post" action="/start"
input type="submit" value="Start"
form method="post" action="/stop"
input type="submit" value="Stop"
This will be rendered into html with two forms with buttons, which will post into /start and /stop on submit. You can run it with just
ruby myapp.rb
This will start a web server on port 4567. Just go to localhost:4567 and press the buttons. Now you can just add actions you need to perform instead of puts "Starting..." and puts "Stopping..." and customize this very basic look of your webapp.
Related
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.
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.
I'm trying to make my sinatra app show a custom error page when an error is raised on the server (e.g. an IOError or ArgumentError).
Currently I'm using AJAX to load the results into a certain #results div, but if and when an error arises on the server, I would like an error page to open up on a new page.
Currently, the IOError is shown on the server and a error is seen in the console (the server responded with a status of 500 (Internal Server Error)). Other than that, nothing happens.
I think that I have to play about with the Javascript (as well as the Sinatra::Base class) but I've spent the whole of yesterday and this morning not getting anywhere.
I would be very grateful for any help. I've created an oversimplified version of my app which I have shown below...
Sinatra_app.rb
require 'sinatra/base'
require9 'sinatra'
require 'slim'
# A helper module
module GVhelpers
def create_results(name)
# raise IOError, "There's a problem..."
return "<p>The Server Says 'Hey #{name}'</p>"
end
end
class GVapp < Sinatra::Base
helpers GVhelpers
set :root, File.dirname(__FILE__)
error do
#error = env['sinatra.error']
slim :"500", :locals => {:error => error}
end
get '/' do
slim :index
end
post '/form' do
name = params[:personName]
create_results(name)
end
end
GVapp.run!
index.slim (in views folder)
script src="/jquery.min.js"
script src="/Gvapp.js"
form#sayHey action="/form" method="post"
| Name:
input type="text" name="personName"
br
input type="submit"
#output
500.slim (in views folder)
h1 Oops! Something went Wonky!
p Apologies, there was an error with your request:
strong request.env['sinatra.error'].message
p If the error persists, please contact the administrator.
Gvapp.js (in public folder)
$(document).ready(function() {
$('#sayHey').submit(function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '/form',
data: $('#sayHey').serialize(),
success: function(response){
$('#output').html(response);
}
})
})
})
Sinatra swallows exceptions when run in the development environment by default and shows its debugging error page instead. So, to trigger your custom error handlers, you have to either run the application inside a Rack environment other than development (probably production), or preferably, tell Sinatra to not use its default error handlers in development mode.
Consider the following, standalone Sinatra application example:
require "sinatra"
#disable :show_exceptions
get "/" do
raise RuntimeError.new("boom")
end
error RuntimeError do
"A RuntimeError occured"
end
If you run this application using the default development environment like this:
$ ruby foo.rb
Then you will get Sinatra’s default error page. If you uncomment the disable line in the example, the error handler will be triggered instead, displaying a page containing "A RuntimeError occured". Alternatively, you can, as explained, run the application in an environment other than development as only that one pre-sets the show_exception setting. You can do that by setting the RACK_ENV environment variable:
$ RACK_ENV=production ruby foo.rb
For development purposes, setting RACK_ENV to production is not the correct way of course. Use disable :show_exceptions instead. You can use a configure block as outlined in the Sinatra README to conditionally disable the setting for the development environment.
configure :development do
disable :show_exceptions
end
That behaviour is documented in Sinatra’s documentation on configuration, along with several other useful settings.
I am creating a Ruby command line application that will generate a Rack application. I want to test that the Rack application that is created is a valid Rack application. I have started using Aruba and Cucumber to test that the CLI creates the correct files and directory structure, but now I'm ready to run rackup and see that the application is running correctly. How can I get Cucumber and Capybara to interact with this newly created application?
Generate a root page for your rack application then have capybara visit whatever path you deem to be your root path and verify some sort of output on that page
def response
if request.path "/"
Rack::Response.new(render("index.html.erb"))
else
Rack::Response.new("Not Found", 404)
end
end
on rack startup: #startup_output = "foo"
generate some sort of output on your root page <%= #startup_output %>
capybara:
visit('/')
page.should have_content('foo')
If you need to have capybara start the app up try using a rake task inside the test:
system "rake rack:start"
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.