Use PORT environment variable in Rack/Sinatra - ruby

I'm looking to set the listening port within my Rack and Sinatra app, using the PORT environment variable if set otherwise to a default.
I thought I may be able to do something like the following but I'm unsure if this is even the right approach.
class ApplicationController < Sinatra::Base
set :port, ENV['PORT'] || 3000
get '/' do
'Hello, World!'
end
end
This doesn't seem to work, at least not with the rackup command. What's the correct way to do this?

rackup takes -p PORT argument.
You can do:
rackup -p $PORT
In config.ru you can also define the options in a comment on the first line:
#\ -p 9090
I'm not sure if that can handle $PORT.
If you look at the source code for rackup, it's very simple:
#!/usr/bin/env ruby
# frozen_string_literal: true
require "rack"
Rack::Server.start
That's the whole file.
Rack::Server.start accepts an options hash as parameter and one of the options is :Port.
You could make your own start.sh that says:
#!/usr/bin/env ruby
# frozen_string_literal: true
require "rack"
Rack::Server.start(Port: ENV['PORT'] || 3000)

Related

set server options inside rackup file

I'm trying set the server options I.E. port, host, etc but I can't find anything on how to do this from within the config.ru file.
I've tried putting the config options into a hash and then doing:
configure { set :server, config[:server][:handler].to_sym }
Rack::Handler.default.run(App, config[:server])
Also tried:
Rack::Handler::pick(['puma']).run App, config[:server]
and even:
configure { set :server, config[:server].delete(:handler).to_sym }
so that the handler won't be in the server config hash and still...
no dice.
config hash is:
{
:handler => "puma",
:host => "127.0.0.1",
:port => 3000,
:threads => "0:16",
:verbose => true
}
But the hash config just gets ignored, I set the port to 3000 but the app loads with 8080 as default.
It also errors about there not being a run command present (well obviously, I'm not using it).
So a fix for that would also be a nice.
I'm sure there's a proper way to do this but why is it so hard to find it documented? I've done as many search terms into google as I can think of and yet nothing completely correct comes back.
It's not documented well because most people don't do what you're trying to do. :-) Folks typically store their Puma configuration in config/puma.rb or pass it on the command line e.g. in Procfile.
I'm going to out on a limb here and assume your App is a Sinatra app or something similar. The main issue with trying to set these options in a Sinatra configure {} block is that by the time rackup is running the class and executing these statements it's already too late to set things like the port and thread pool size. As far as the missing run method goes, I think you just want run App in config.ru. Not sure what you're going for there.
You can tell rackup to use Puma by adding this at the top of the file:
#\ -s Puma
If you want to set the port or any other rackup options, you can do it like so:
#\ -s Puma -p 3000
or, for Puma-specific options:
#\ -s Puma -p 3000 -O Threads=0:16 -O Verbose=true
This is (mostly) documented in Puma's README here, and here.
Another option is to skip rackup and config.ru entirely and just build everything into your Sinatra app:
require 'sinatra/base'
require 'puma'
class App < Sinatra::Application
configure do
set :server, :puma
set :port, 3000
set :server_settings, :Threads => '0:16', :Verbose => true
end
run! if $0 == app_file
end
Then you can just run your app like any normal Ruby script, e.g. ruby app.rb.
At the end of the day, I would strongly recommend you explore creating a Puma configuration file and using that instead. It's just easier, cleaner, and more understandable. If you need to pull in the Puma settings from the environment or from the result of another method or process, you can do that in there. Best of luck.
You can specify options on a line staring with #\ in config.ru (it must be the first such line). You specify them as if you were specifying command line options to rackup:
#\ -s puma -o 127.0.0.1 -p 3000 -O Threads=0:16 -O Verbose
# require everything and set up middleware etc.
run MyApp
The docs for this are hidden away on the wiki.
Check rackup -s puma -h for the options you can use. -O passes the option through to the server you are using (Puma seems to accept Threads and Verbose).

Sinatra app executes during load instead of after run method issued

This is a stripped down example of a real app I am building. When I execute my app, this is the result I get. You'll notice that it says that it is running before it is starting. You'll also notice it never says running after the start is issued.
bundle exec rackup
Using thin;
Sapp::App running.
Starting Sapp::App
== Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.7.0 codename Dunder Mifflin)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
My config.ru is:
# http://www.rubydoc.info/gems/webmachine/Webmachine/Adapters/Rack
$started = false
require 'thin'
require 'sinatra'
set :server, (ENV['RACK_ENV'] == 'production' || ENV['RACK_ENV'] == 'staging' ? 'rack' : 'thin')
puts "Using #{settings.server};"
load 'webmachine/adapters/rack.rb'
load File.join(File.dirname(__FILE__), 'sapp.rb')
$started = true
puts 'Starting Sapp::App'
#Sapp::App.run!
Sinatra::Application.run!
I am setting $started just to try to fix this problem, but it doesn't help. My app is executed before it is set. I could control that but, and this is the rub, it does not execute after the run is issued.
sapp.rb is:
ENV['RACK_ENV'] ||= 'development'
Bundler.setup
$: << File.expand_path('../', __FILE__)
$: << File.expand_path('../lib', __FILE__)
require 'dotenv'
Dotenv.load(
File.expand_path("../.env.#{ENV['RACK_ENV']}", __FILE__),
File.expand_path("../.env", __FILE__))
module Sapp
class App < Sinatra::Application
puts 'Sapp::App has been started.' if $started
puts 'Sapp::App running.'
end
end
In the end, if nothing else, Once it says "Starting Sapp::App", it should also say "Sapp::App has been started." and "Sapp::App running."
For the record, both these options do the same thing:
Sapp::App.run!
Sinatra::Application.run!
Okay, I get it. I put the code in a class, but not it a method. Load or require both run open code like this. I need to wrap it in methods, and execute the methods, to do what I want to do.
Sinatra examples, which I followed, don't make this clear and simply avoid the topic. Many are so simple it doesn't make a difference, and some are just coded within the config.ru. I am coming from Rails and, while I knew this from Rails, it didn't make much of a difference since the vast majority of the code already exists in methods.

Ruby oci8 fails when using dotenv for password

I'm attempting to use the dotenv gem to securely store a password for an oci8 connection. My .env file looks like this:
# this file is stored in the same location as config.ru
SCOTT_PASS='tiger'
Here's my config.ru file:
require 'dashing'
require 'dotenv'
Dotenv.load
configure do
set :auth_token, 'YOUR_AUTH_TOKEN'
helpers do
def protected!
# Put any authentication code you want in here.
# This method is run before accessing any resource.
end
end
end
map Sinatra::Application.assets_prefix do
run Sinatra::Application.sprockets
end
run Sinatra::Application
Here's the job which is failing. It fails with a null password error (ORA-01005).
SCHEDULER.every '1m', :first_in => 0 do |job|
conn = OCI8.new('scott', ENV['SCOTT_PASS'], 'orcl')
cursor = conn.parse("SELECT COUNT(*) FROM USER_TABLES")
cursor.exec
r = cursor.fetch
send_event('table_count', { current: r })
cursor.close
conn.logoff
end
I was able to confirm Dotenv.load is working properly as I was able to set other variables successfully, so there seems to be something unique about the oci8 connection.
I'm new to both Ruby and programming, so I might be overlooking something simple. Thanks!
This was a fairly obscure issue, but the root cause was due to a complex password being used (alpha numeric and special characters). The same password worked correctly in a small ruby script, but fails when placed under the rufus scheduler. Switching to a 20+ character password without numbers or special characters resolved the issue. Guessing there might some type of escaping required.

How can I execute Ruby code with WEBrick instead of dumping the code to my browser?

I'm facing a problem when I run my program in a browser with the WEBrick server. It shows me my code as written in the 2loop.rb file.
When I run ruby -run -e -httpd. -p 5000 at the command prompt, and load http://localhost:5000/2loop.rb in the browser, it shows the code from 2loop.rb instead of running it.
How can I execute the 2loop.rb program instead?
TL;DR
You're doing this to yourself by serving your current working directory as the root of your web server. You aren't actually running the code in your file; you're just telling WEBrick to serve any file you name in the URI. http://localhost:5000/2loop.rb will serve "2loop.rb" as text/html in your posted example.
Using un.rb
The flag you're using isn't actually "run." Instead, the -r flag actually loads a module, which in this case is the un.rb module. Using un.rb to start WEBrick is done like this:
$ ruby -run -e httpd . -p 5000
and starts a web server in the document root. In this case, the dot means to use the current working directory as the root. This is not really what you want to start code you've placed inside a Ruby file.
Running WEBrick Programmatically
Using some snippets from the WEBrick documentation, you will see that you can create a file named "2loop.rb" containing the following:
#!/usr/bin/env ruby
require 'webrick'
root = File.path '/tmp/public_html'
server = WEBrick::HTTPServer.new :Port => 5000, :DocumentRoot => root
trap 'INT' do server.shutdown end
server.start
This will serve files out of the /tmp/public_html directory on port 5000, which you can reach at http://localhost:5000. You can then make the file executable and start the server with ./2loop.rb, or just run ruby 2loop.rb if you don't want to make your file executable for some reason.
If you don't want WEBrick just to serve files, you will have to add custom behavior to your web server inside the 2loop.rb script. This is a fairly low-level thing to do, but may suit your needs.
Sensible Alternatives
You should probably use a web framework like Ruby on Rails or Sinatra if you don't want to have write all the low-level behaviors yourself. Sinatra in particular is a very lightweight alternative. This example:
#!/usr/bin/env ruby
require 'sinatra'
set :port, 5000
get '/hello' do
"Hello, World!"
end
will create a URL at http://localhost:5000/hello with a custom action that returns "Hello, World!" as an in-browser response.
Well, I'd suggest you to use Common Gateway Interface (CGI). Let me provide you an example.
Firstly, create a file named server.rb:
require 'webrick'
server = WEBrick::HTTPServer.new(
:Port => 6789, # a server's port
:DocumentRoot => File.join(Dir.pwd, "/scripts") # a folder with scripts
)
server.start
Secondly, create a folder scripts and put the following file (the_best_program.cgi) into it. Note the .cgi extension. It matters. Look here for details on the first line of the script (shebang) if you are working under Windows.
#!/usr/bin/env ruby
require 'cgi'
print "Content-type: text/plain\n\n"
5.times { |i| puts "Hello world #{i}!"}
puts 'So many worlds there. :('
Finally,
Launch your server from command-line (ruby server.rb).
Start browser and go to localhost:6789/the_best_program.cgi (or 0.0.0.0:6789/the_best_program.cgi)
Enjoy!
Notes
You might need to change permissions to your scripts folder / script. On unix-like system do: chmod 755 scripts scripts/the_best_program.cgi.
You can launch not only ruby scripts this way.

How do I globally configure RSpec to keep the '--color' and '--format specdoc' options turned on

How do I set global configuration for RSpec in Ubuntu.
Specifically so, --color and --format specdoc stay turned on, across all my projects (ie every time I run rspec anywhere).
As you can see in the docs here, the intended use is creating ~/.rspec and in it putting your options, such as --color.
To quickly create an ~/.rspec file with the --color option, just run:
echo '--color' >> ~/.rspec
One can also use a spec_helper.rb file in all projects. The file should include the following:
RSpec.configure do |config|
# Use color in STDOUT
config.color = true
# Use color not only in STDOUT but also in pagers and files
config.tty = true
# Use the specified formatter
config.formatter = :documentation # :progress, :html,
# :json, CustomFormatterClass
end
Any example file must require the helper to be able to use that options.
In your spec_helper.rb file, include the following option:
RSpec.configure do |config|
config.color_enabled = true
end
You then must require in each *_spec.rb file that should use that option.
If you use rake to run rspec tests then you can edit spec/spec.opts
http://rspec.info/rails/runners.html
Or simply add alias spec=spec --color --format specdoc to your ~/.bashrc file like me.
One thing to be aware of is the impact of the different ways of running RSpec.
I was trying to turn on the option with the following code in spec/spec_helper.rb -
Rspec.configure do |config|
config.tty = $stdout.tty?
end
calling the 'rspec' binary directly - or as 'bundle exec rspec' and checking $stdout.tty? will return true.
invoking the 'rake spec' task - or as 'bundle exec rake spec' - Rake will invoke rspec in a separate process, and $stdout.tty? will return false.
In the end I used the ~/.rspec option, with just --tty as its contents. Works well for me and keeps our CI server output clean.

Resources