Using custom classes with Sinatra - ruby

I'm developing a Sinatra application. To simplify the structure for an easier future support I added a few custom classes, located in separate files. What I'm trying to do is to make them use existing helpers and sinatra's own functionality (models, sessions, etc) without repeating the code.
For example, I have a helper to_html(text) and I'd like to use it both inside sinatra routes and in my own classes, which are also to be used inside routes.
My sinatra app is written in classic style (if it matters for your suggestion).
Is it possible?

Assuming you have a helpers directory in the root of the project, you could do something like this from inside your app file you use to run the server.
%w(helpers).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
You will need to include your routes below this for it to work. To make this even cleaner, you can also have a routes/controllers directory. Simply add 'routes' to that array as such:
%w(helpers routes).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
This will require all of your helpers THEN your routes.

Related

serving static files on sinatra

I'm working on a Sinatra app for the first time and am stumbling into an issue with serving a javascript asset.
I am following the Sinatra convention of putting the static files in “public” folder and it works locally but when we create a Docker image, we get a 404 while this works with localhost.
I see where I can set the public_folder which I have tried like this:
http://sinatrarb.com/configuration.html
but still 404'ing. Is there a way to get the top-level object and ask it where it expects the public_folder to be (like Rails.env)?
You can check the settings object.
irb(main):001:0> require "sinatra"
=> true
irb(main):002:0> settings.public_folder
=> "/usr/lib/ruby/2.5.0/irb/public"
This allows you to create a route which returns the path, something like this
require 'sinatra'
get '/' do
settings.public_folder
end
Without more information I would guess that your public folder points to a wrong directory inside your docker because the project :root points to a different directory that what you expect.

Sinatra API Versioning

I'm new to APIs and Sinatra and I was wondering if there are any good gems for properly versioning a REST API using Sinatra. I'm using a namespace right now like this:
namespace '/api/v1' do
#routes and stuff here
end
So if I had a version 2, I would just have to create another namespace I suppose.
In your config.ru file, you can specify the mapping:
map('/v2') { run ClassNameV2 }
map('/v1') { run ClassNameV1 }

Which is the right path to place an initializer in a Padrino sub application

I'm working with OmniAuth-Facebook and initializing it in mysubapp/app.rb:
require 'omniauth-facebook'
class MySubApp < Padrino::Application
register Padrino::Rendering
register Padrino::Mailer
register Padrino::Helpers
enable :sessions
SCOPE = 'email,read_stream'
ENV['APP_ID'] = '111111111111111'
ENV['APP_SECRET'] = '11111111111111111111111111111111'
use OmniAuth::Builder do
provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => SCOPE
end
end
I just want to know if this is the way you should work with Padrino. Is this the right place to put my initializers or, maybe, you can create an specific sub-application config.ru?
Placing code into boot.rb for multi-app deployments, or in the apps app.rb is the correct place to put things.
If you like things looking cleaner you could create a new config/initializers directory then add the following to boot.rb
Padrino.require_dependencies "#{Padrino.root}/config/initializers/**/*.rb"
Here is the Padrino guide for Special Folders which as a little bit more about loading or requiring additional paths.

Two Sinatra Apps, shared datamapper DB

I'm trying to think of a good way of using Sinatra and Datamapper to create a solid web app that shares a database. I started using just one app, but I'm thinking about splitting the admin aspect to it's own app with a different mapping in a config.ru file.
So, config.ru will map the root route to the main app, and '/admin' to the Admin app. The main app will be responsible for showing data from the db to any user, and the Admin app is responsible for allowing admins to add content to the db. My reasoning behind this is to allow me more flexibility and reusability with the admin app.
The main app has the Datamapper classes responsible for defining my model, though I am sure I could move that to the admin app without a problem. Is there a way/reason to move it to it's own separate .rb file?
Obviously new to this platform, but I'm loving it. Any help is greatly appreciated.
You can have one project with as many sinatra apps as you like. for your project, you can set it up like this:
# site.rb
require 'config/boot'
class Site < Sinatra::Base
...
end
# admin.rb
require 'config/boot'
class Admin < Sinatra::Base
...
end
# config/boot.rb
require 'model/user.rb'
require 'model/post.rb'
# config.ru
require 'admin'
require 'site'
run Rack::URLMap.new("/" => Site.new, "/admin" => Admin.new)
The key is to put both apps in the same project / version control.

Multiple Sinatra apps using rack-mount

I have a question regarding using rack-mount with Sinatra. I've got two classic-style Sinatra apps. Let's call one App defined in app.rb and the other API defined in api.rb.
I would like it so that api.rb handles all routes beginning with '/api' and app.rb handles all other requests including the root ('/').
How would I set this up with rack-mount? Or is there a better solution than that?
I think you'll prefer Rack::URLMap - it will probably look something like this:
run Rack::URLMap.new("/" => App.new,
"/api" => Api.new)
That should go in your config.ru file.
I had a similar issue and I am not very familiar with Rack. I could not figure out what to do based on the answers above. My final solution was to have the following in config.ru.
This works perfectly for me.
# Main Ramaze site
map "/" do
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
require ::File.expand_path('../app', __FILE__)
Ramaze.start(:root => __DIR__, :started => true)
run Ramaze
end
# Sinatra & Grape API
map "/api" do
use Rack::Static, :urls => ["/stylesheets", "/images", "/javascripts"], :root => "public"
use Rack::Session::Cookie
run Rack::Cascade.new([
MySinatraApp::Application,
MySinatraApp::API])
end
In config.ru you could also take advantage of Sinatra's middleware feature. If you have several Sinatra apps, each with its own routes, and want to run them simultaneously, you can arrange them in the order you want them found, e.g.
# config.ru
...
use MyAppA
use MyAppB
use MyAppC
run MyAppD
I had the same problem once and so I came up with this template: sinatra-rspec-bundler-template which is layed out for multiple apps.
It may have more features than you need but it should help you when you need something "a bit more" complex.

Resources