Why don't instance variables persist between routes in Sinatra? - ruby

I know different ways to make data persist between routes in Sinatra. I'm just trying to understand this more in a Ruby/Object-Oriented way.
My guess is: whenever you rackup a Sinatra app, you're instantiating a Sinatra::Application object. Is it that every time you call a get/post route method, you're creating a new Sinatra::Application so the instance variables will be different?

You're correct. Every time you open a new route, a new instance of your rack/sinatra app is re-instantiated.
You can check this out in a very simple way:
require 'sinatra/base'
class MyApp < Sinatra::Application
get '/' do
puts self.object_id
'Hello world!'
end
end
The output i get from this when opening the browser twice at "localhost:9292" is:
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on 0.0.0.0:9292, CTRL+C to stop
70308503790680
127.0.0.1 - - [21/Jun/2014 16:10:21] "GET / HTTP/1.1" 200 12 0.0129
70308504166760
127.0.0.1 - - [21/Jun/2014 16:10:22] "GET / HTTP/1.1" 200 12 0.0016
Focus on the fourth and sixth line: you can see that the instances have different ids.
If you just output self, you can see that it's an instance of the MyApp class:
#<MyApp:0x007fbfea3a87c8>
127.0.0.1 - - [21/Jun/2014 16:19:54] "GET / HTTP/1.1" 200 12 0.0124
#<MyApp:0x007fbfea460198>

Related

Router file in Ruby webserver

PHP has a built in webserver (Example #3) where you can pass in a router file as an argument. Every request will go through that router file where you can do all kinds of things with the request.
php -S localhost:8000 router.php
The router file could look like this:
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
return false; // serve the requested resource as-is.
} else {
echo "<p>Welcome to PHP</p>";
}
?>
Is that also possible with a Ruby webserver like Thin?
Thanks!
This sounds a lot like sinatra, which is a very lightweight web framework for ruby.
For example, in a ruby file (say it's called server.rb):
require 'sinatra'
get "/" do
"hello world"
end
get "/:foo" do
"you typed #{params[:foo]}"
end
and in the terminal:
ruby server.rb
# => listening on port 4567
You can test it by going to localhost:4567 in the browser.
In your case I will use rack, this is a ruby:
Rack includes handlers that connect Rack to all these web application servers (WEBrick, Mongrel etc.).
Rack includes adapters that connect Rack to various web frameworks (Sinatra, Rails etc.).
Between the server and the framework, Rack can be customized to your applications needs using middleware.
In order to use rack you must create rack application:
must answer call method.
The call mehtod is called by the server and must recevive an env variable with the CGI information.
Must return an array with 3 elements:
a) status: integer
b) headers: hash
c) body: An object that responds to each and for every call to each retuns a String.
The fundamental idea behind Rack middleware is – come between the calling client and the server, process the HTTP request before sending it to the server, and processing the HTTP response before returning it to the client.
this is the basic, answer of your question:
test_rack.rb
class MyApp
def call env
[200, {"Content-Type" => "text/html"}, ["Hello Rack Participants"]]
end
end
config.ru
require './test_rack.rb'
run MyApp.new
then start up the application, and make a call to localhost:9292/anything
╭─toni#Antonios-MBP ~/learn/ruby/stackoverflow/scripting ‹ruby-2.2.3#stackoverflow› ‹1.7› ‹SBCL 1.3.5›
╰─$ rackup config.ru
[2016-05-08 11:17:41] INFO WEBrick 1.3.1
[2016-05-08 11:17:41] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2016-05-08 11:17:41] INFO WEBrick::HTTPServer#start: pid=2610 port=9292
::1 - - [08/May/2016:11:18:04 +0200] "GET /patata HTTP/1.1" 200 - 0.0010
::1 - - [08/May/2016:11:18:04 +0200] "GET /favicon.ico HTTP/1.1" 200 - 0.0005
::1 - - [08/May/2016:11:18:09 +0200] "GET /patata/calimero HTTP/1.1" 200 - 0.0003
let's see rack working in console, see the multiple webservers and pass lambda for create the call function
require 'rack'
=> true
irb(main):010:0> Rack::Handler::constants
=> [:CGI, :FastCGI, :Mongrel, :EventedMongrel, :SwiftipliedMongrel, :WEBrick, :LSWS, :SCGI, :Thin]
irb(main):026:0> Rack::Handler::WEBrick.run lambda { |env| [200,{"Content-Type" => "text/plain"}, ["Hello. The time is #{Time.now}"]] }
[2016-05-08 11:22:39] INFO WEBrick 1.3.1
[2016-05-08 11:22:39] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin15]
[2016-05-08 11:22:39] INFO WEBrick::HTTPServer#start: pid=1798 port=8080
to go further:
https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware
https://github.com/rack/rack

Sinatra show view /example/:id returns 404 error for assets, when using sprockets

When I am accessing:
get "/example/:id" do
...
slim :'example/show'
end
I am getting this error:
"GET /example/assets/app.css HTTP/1.1" 404
"GET /example/assets/app.js HTTP/1.1" 404
I am suspecting that :id can be a problem here, because
my assets setup works when I am accessing:
get "/example" do
...
slim :'example/index'
end
works:
"GET /assets/app.css HTTP/1.1" 304
"GET /assets/app.js HTTP/1.1" 200
My setup for sprockets:
class App < Sinatra::Base
set :environment, Sprockets::Environment.new
environment.append_path "assets/stylesheets"
environment.append_path "assets/javascripts"
environment.js_compressor = :uglify
environment.css_compressor = :scss
get "/assets/*" do
env["PATH_INFO"].sub!("/assets", "")
settings.environment.call(env)
end
...
end
My full repo but without last changes: https://github.com/aneta-bielska/home-for-paws-app
In your layout you have the following lines which define the links to your assets:
link rel="stylesheet" href="assets/app.css"
script src="assets/app.js"
Since the urls in these elements don’t start with a slash, the browser treats them as relative to the page where they appear. This means that when you visit /example the links go to /assets/app.cs and /assets/app.js. However when you go to e.g example/1 the links are treated as relative to the 1, so the browser tries to fetch /example/assets/app.cs (and similarly for app.js).
You need to make sure theses links are always treated as absolute. The simplest way would be to just add a / at the start:
link rel="stylesheet" href="/assets/app.css"
script src="/assets/app.js"
A more robust solution might be to use Sinatra’s url helper to ensure you always create the correct links, as it will take it account mounting the app at different paths on the server:
link rel="stylesheet" href=url("/assets/app.css")
script src=url("/assets/app.js")

Sinatra logging outside request

I believe I'm missing something with the way Sinatra does logging. I'd like to define a custom logger but also use it outside Sinatra's routes.
My app.rb looks like this:
require 'sinatra'
require 'logger'
logger = Logger.new(STDOUT)
configure do
use Rack::CommonLogger, logger
end
get '/' do
logger.info 'In request'
'Hello, world!'
end
logger.info 'Outside request'
The config.ru like so:
require 'sinatra'
require_relative 'app'
configure do
enable :logging
end
run Sinatra::Application
But when I run the application and curl the URL, I only see the log out during the request, not logger.info 'Outside request' when the application loads.
$ bundle exec rackup
I, [2015-06-22T23:09:32.789802 #6122] INFO -- : Outside request
[2015-06-22 23:09:32] INFO WEBrick 1.3.1
[2015-06-22 23:09:32] INFO ruby 2.1.4 (2014-10-27) [x86_64-linux]
[2015-06-22 23:09:32] INFO WEBrick::HTTPServer#start: pid=6122 port=9292
::1 - - [22/Jun/2015:23:09:48 -0400] "GET / HTTP/1.1" 200 13 0.0059
::1 - - [22/Jun/2015:23:09:48 -0400] "GET / HTTP/1.1" 200 13 0.0124
Hello, world!%
I know I'm missing something fundamental here, any help would be appreciated. Thank you.

Sinatra `map` not working

I'm trying to run sinatra behind a proxy, at the url http://server/project/, so that GET http://server/project/foo goes to /foo in the app. My config.ru looks like this:
map('/project') { run App }
I see in the log "GET /project/ HTTP/1.1" 404; even though i have a GET '/' method defined. It works when run normally (just run App without the map call). I can't figure out why.

How to customize Sinatra logging level

I redirected Sinatra output to log file. I was wondering how to skip all requests and write only errors Eg.
localhost - - [22/Dec/2010:15:47:32 AUSEDT] "GET /db/OMSGDV03/tlm HTTP/1.1" 200 93
- -> /A/B/C
shouldn't appear
You can turn off requests logging with:
set :logging, false

Resources