Using Sinatra for larger projects via multiple files Using Sinatra for larger projects via multiple files ruby ruby

Using Sinatra for larger projects via multiple files


Here is a basic template for Sinatra apps that I use. (My larger apps have 200+ files broken out like this, not counting vendor'd gems, covering 75-100 explicit routes. Some of these routes are Regexp routes covering an additional 50+ route patterns.) When using Thin, you run an app like this using:
thin -R config.ru start

Edit: I'm now maintaining my own Monk skeleton based on the below called Riblits. To use it to copy my template as the basis for your own projects:

# Before creating your projectmonk add riblits git://github.com/Phrogz/riblits.git# Inside your empty project directorymonk init -s riblits

File Layout:

config.ruapp.rbhelpers/  init.rb  partials.rbmodels/  init.rb  user.rbroutes/  init.rb  login.rb  main.rbviews/  layout.haml  login.haml  main.haml

 
config.ru

root = ::File.dirname(__FILE__)require ::File.join( root, 'app' )run MyApp.new

 
app.rb

# encoding: utf-8require 'sinatra'require 'haml'class MyApp < Sinatra::Application  enable :sessions  configure :production do    set :haml, { :ugly=>true }    set :clean_trace, true  end  configure :development do    # ...  end  helpers do    include Rack::Utils    alias_method :h, :escape_html  endendrequire_relative 'models/init'require_relative 'helpers/init'require_relative 'routes/init'

 
helpers/init.rb

# encoding: utf-8require_relative 'partials'MyApp.helpers PartialPartialsrequire_relative 'nicebytes'MyApp.helpers NiceBytes

 
helpers/partials.rb

# encoding: utf-8module PartialPartials  def spoof_request(uri,env_modifications={})    call(env.merge("PATH_INFO" => uri).merge(env_modifications)).last.join  end  def partial( page, variables={} )    haml page, {layout:false}, variables  endend

 
helpers/nicebytes.rb

# encoding: utf-8module NiceBytes  K = 2.0**10  M = 2.0**20  G = 2.0**30  T = 2.0**40  def nice_bytes( bytes, max_digits=3 )    value, suffix, precision = case bytes      when 0...K        [ bytes, 'B', 0 ]      else        value, suffix = case bytes          when K...M then [ bytes / K, 'kiB' ]          when M...G then [ bytes / M, 'MiB' ]          when G...T then [ bytes / G, 'GiB' ]          else            [ bytes / T, 'TiB' ]        end        used_digits = case value          when   0...10   then 1          when  10...100  then 2          when 100...1000 then 3          else 4        end        leftover_digits = max_digits - used_digits        [ value, suffix, leftover_digits > 0 ? leftover_digits : 0 ]    end    "%.#{precision}f#{suffix}" % value  end  module_function :nice_bytes  # Allow NiceBytes.nice_bytes outside of Sinatraend

 
models/init.rb

# encoding: utf-8require 'sequel'DB = Sequel.postgres 'dbname', user:'bduser', password:'dbpass', host:'localhost'DB << "SET CLIENT_ENCODING TO 'UTF8';"require_relative 'users'

 
models/user.rb

# encoding: utf-8class User < Sequel::Model  # ...end

 
routes/init.rb

# encoding: utf-8require_relative 'login'require_relative 'main'

 
routes/login.rb

# encoding: utf-8class MyApp < Sinatra::Application  get "/login" do    @title  = "Login"    haml :login  end  post "/login" do    # Define your own check_login    if user = check_login      session[ :user ] = user.pk      redirect '/'    else      redirect '/login'    end  end  get "/logout" do    session[:user] = session[:pass] = nil    redirect '/'  endend

 
routes/main.rb

# encoding: utf-8class MyApp < Sinatra::Application  get "/" do    @title = "Welcome to MyApp"            haml :main  endend

 
views/layout.haml

!!! XML!!! 1.1%html(xmlns="http://www.w3.org/1999/xhtml")  %head    %title= @title    %link(rel="icon" type="image/png" href="/favicon.png")    %meta(http-equiv="X-UA-Compatible" content="IE=8")    %meta(http-equiv="Content-Script-Type" content="text/javascript" )    %meta(http-equiv="Content-Style-Type" content="text/css" )    %meta(http-equiv="Content-Type" content="text/html; charset=utf-8" )    %meta(http-equiv="expires" content="0" )    %meta(name="author" content="MeWho")  %body{id:@action}    %h1= @title    #content= yield


Absolutely. To see an example of this I recommend downloading the Monk gem, described here:

https://github.com/monkrb/monk

You can 'gem install' it via rubygems.org. Once you have the gem, generate a sample app using the instructions linked above.

Note that you don't have to use Monk for your actual development unless you want to (in fact I think it may not be current). The point is to see how you can easily structure your app in the MVC style (with separate controller-like route files) if you want to.

It's pretty simple if you look at how Monk handles it, mostly a matter of requiring files in separate directories, something like (you'll have to define root_path):

Dir[root_path("app/**/*.rb")].each do |file|    require fileend


Do a Google search for "Sinatra boilerplate" to get some ideas for how others are laying out their Sinatra applications. From that you can probably find one that suits your needs or simply make your own. It's not too hard to do. As you develop more Sinatra apps, you can add to your boilerplate.

Here's what I made and use for all of my projects:

https://github.com/rziehl/sinatra-boilerplate