issues finding public folder when requiring sinatra/base - ruby

I have found that in my Sinatra app, when I require 'sinatra', I can access my public folder as expected, but when I require 'sinatra/base' I can't. Here is my relevant code (which works until I change to /base):
config.ru
root = ::File.dirname(__FILE__)
require ::File.join( root, 'app' )
run MyApp.new
app.rb
require 'sinatra'
require 'sinatra/namespace'
require 'haml'
class MyApp < Sinatra::Application
# ...
end
require_relative 'models/init'
require_relative 'helpers/init'
require_relative 'routes/init'
script.haml
%script(type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js")
%script(type="text/javascript" src="/js/table.js")
%link(rel="stylesheet" type="text/css" href="/css/table.css")
And yes, I have the correct directory structure in place. Like I said, it works using require sinatra. Anyone know why this is occurring and what I can do to fix it?

Requiring Sinatra::Base does not set any of the default configuration settings that requiring Sinatra does. You'll need to set :public_folder ... to a suitable value yourself, e.g:
set :public_folder, 'public'

Related

Sinatra - ActiveRecord::ConnectionNotEstablished: No connection pool for ActiveRecord::Base

I've only been able to find rails answers to this question. Whenever I run rake db:migrate I am getting the aforementioned error. As far as I am aware, I have setup everything correctly so have no idea what's wrong.
config/environment.rb
ENV['SINATRA_ENV'] ||= "development"
require 'bundler/setup'
Bundler.require(:default, ENV['SINATRA_ENV'])
configure :develpoment do
set :database, 'sqlite3:db/database.db'
end
require './app'
Rakefile
require "./config/environment"
require "sinatra/activerecord/rake"

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.

Environment configuration for Sinatra error

I have an environment config file at config/environment.rb with the following:
require 'rubygems'
require 'bundler'
Bundler.setup
require 'sinatra'
require 'sinatra/base'
require 'sinatra/reloader'
and in my config.ru I have:
require File.expand_path('../config/environment', __FILE__)
require 'slim'
require 'coffee-script'
require 'padrino-helpers'
require 'sinatra/twitter-bootstrap'
I am getting the error :
Errno::ENOENT at /profile
No such file or directory - /Users/myusername/projects/accounts/config/views/profile.slim
and this only goes away when I remove require 'sinatra' from the config/environment.rb file and into config.ru. Can anyone explain why this happens? I assumed that the require File.expand_path('../config/environment', __FILE__) will simply include all requires from that file into config.ru but that doesn't seem to be the case. It now thinks my views live inside the config folder.
I followed the suggestion given here: How do I make Rake tasks run under my Sinantra app/environment? but again, moving require 'sinatra' into the environment breaks the app.
The error looks like it is from Sinatra being unable to find a Slim template when rendering a response, because it’s looking for a views directory under the config directory. By default Sinatra looks for the views dir relative to the application file, which (again by default) is the file that calls require 'sinatra'. In your case the require line is in config/environment.rb so Sinatra treats that as the app file and looks for the views dir below it.
I’m assuming you have an actual application file that you haven’t shown. The simplest solution is probably to explicitly set the application file setting in there:
set :app_file, __FILE__
Depending on your setup you might want to specify the view directory directly instead:
set :views, 'path/to/views'

Sinatra commands do not work in modules

I have a Sinatra app which requires a module in a different file. When I use Sinatra commands in that module (e.g. redirect "http://facebook.com"), I get a NoMethodError. To illustrate the problem, I have made a simplified version:
--- mainapp.rb ---
#config
require './redirector.rb'
get '/' do
Redirector::redirect_to_stackoverflow
end
--- redirector.rb ---
module Redirector
require 'sinatra'
def self.redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
--- config.ru ---
require 'rubygems'
require 'sinatra'
require File.dirname(__FILE__) + "/ptt.rb"
run Sinatra::Application
What is wrong? Is there a place where I haven't required something properly?
The call to redirect inside the Redirector module is sent to the Redirector Module object, where the method does not exist. require 'sinatra' inside module Redirector is not necessary, and does not do any kind of method composition.
You probably could compose Sinatra methods into your Redirector module, but that is not normal practice. Usually it's the other way around - you write "helper" modules that are composed in to your Sinatra application in various ways.
This is a similar example application, with a more usual approach to composition:
app.rb
require 'sinatra'
require_relative 'redirect.rb'
class MyApp < Sinatra::Application
include Redirector
get '/' do
redirect_to_stackoverflow
end
end
redirect.rb
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
config.ru
require File.dirname(__FILE__) + "/app.rb"
run MyApp
#Neil Slater's explanation is correct, but I'd suggest you also make it an Sinatra extension, e.g.
require 'sinatra/base'
module Sinatra
module Redirector
def redirect_to_stackoverflow
redirect "http://stackoverflow.com"
end
end
helpers Redirector
end
Then (for a classic app) all you need to do is require it.
require 'sinatra/redirector'
get "/" do
redirect_to_stackoverflow
end

Sinatra Synchrony with Redis connection pooling

Is this the correct way of handling Redis connection pooling with Sinatra Synchrony?
My gemfile looks like this:
gem 'sinatra-synchrony'
gem 'hiredis'
gem 'redis'
The sinatra server files use the classic style approach, and generally look like so:
require 'sinatra'
require 'sinatra/synchrony'
require 'redis/connection/hiredis'
require 'redis/connection/synchrony'
require 'redis'
redis = EventMachine::Synchrony::ConnectionPool.new(size: 5) do
Redis.new(path: '/tmp/redis.sock')
end
get / do
# lots of redis reads and writes
end
I then launch multiple instances of the same server application, each under a different port, and use nginx to load balance between them.
Is this the proper solution for connection pooling Redis with Sinatra servers?
Here is a working example, I removed sinatra/sinatra because I don't feel it is needed and I couldn't make it works:
Gemfile:
source :rubygems
gem 'thin'
gem 'rack-fiber_pool'
gem 'hiredis'
gem 'sinatra'
gem 'em-synchrony'
gem 'redis'
config.ru:
require 'rubygems'
require 'bundler/setup'
require 'sinatra/base'
require 'redis/connection/synchrony'
require 'redis'
require 'rack/fiber_pool'
class App < Sinatra::Base
set :template_path, '/tmp'
def initialize
super
#redis = EventMachine::Synchrony::ConnectionPool.new(size: 2) do
Redis.new
end
end
get '/' do
#redis.multi do |r|
r.set('v', "value2")
r.set('v2', '43')
end
#redis.get('v')
end
end
use Rack::FiberPool
use Rack::CommonLogger
run App
And run it with (in the same folder):
bundle
bundle exec thin start
In a real application you would remove the application code from the config.ru file and add a require but at least it gives you a start :)

Resources