Using Sinatra for larger projects via multiple fil

2019-01-03 07:18发布

It seems that in Sinatra all route handlers are being written into a single file, if I understand right it acts as a one large/small controller. Is there any way to split it into separate independent files, so when let's say somebody calls "/" - one action is executed, and if smth like "/posts/2" is received then another action - similar logic that is applied in PHP?

标签: ruby sinatra
8条回答
戒情不戒烟
2楼-- · 2019-01-03 07:41

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 file
end
查看更多
祖国的老花朵
3楼-- · 2019-01-03 07:56

I know this is an old query but I still can't believe no one mentioned Padrino You can use it as a framework on top of Sinatra, or piecemeal adding only the gems that interest you. It kicks ten buttloads of ass!

查看更多
叼着烟拽天下
4楼-- · 2019-01-03 07:56

My approach to host different projects on the same site is to use sinatra/namespace in such way:

server.rb

require "sinatra"
require "sinatra/namespace"

if [ENV["LOGNAME"], ENV["USER"]] == [nil, "naki"]
    require "sinatra/reloader"
    register Sinatra::Reloader
    set :port, 8719
else
    set :environment, :production
end

for server in Dir.glob "server_*.rb"
    require_relative server
end

get "/" do
    "this route is useless"
end

server_someproject.rb

module SomeProject
    def self.foo bar
       ...
    end
    ...
end

namespace "/someproject" do
    set :views, settings.root
    get "" do
        redirect request.env["REQUEST_PATH"] + "/"
    end
    get "/" do
        haml :view_someproject
    end
    post "/foo" do
        ...
        SomeProject.foo ...
    end
end

view_someproject.haml

!!!
%html
    ...

Another detail about subprojects I used was to add their names, description and routes to some kind of global variable, that is used by "/" to make a guide homepage, but I don't have a snippet right now.

查看更多
神经病院院长
5楼-- · 2019-01-03 07:57

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 project
monk add riblits git://github.com/Phrogz/riblits.git

# Inside your empty project directory
monk init -s riblits

File Layout:

config.ru
app.rb
helpers/
  init.rb
  partials.rb
models/
  init.rb
  user.rb
routes/
  init.rb
  login.rb
  main.rb
views/
  layout.haml
  login.haml
  main.haml

 
config.ru

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

 
app.rb

# encoding: utf-8
require '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
  end
end

require_relative 'models/init'
require_relative 'helpers/init'
require_relative 'routes/init'

 
helpers/init.rb

# encoding: utf-8
require_relative 'partials'
MyApp.helpers PartialPartials

require_relative 'nicebytes'
MyApp.helpers NiceBytes

 
helpers/partials.rb

# encoding: utf-8
module 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
  end
end

 
helpers/nicebytes.rb

# encoding: utf-8
module 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 Sinatra
end

 
models/init.rb

# encoding: utf-8
require '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-8
class User < Sequel::Model
  # ...
end

 
routes/init.rb

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

 
routes/login.rb

# encoding: utf-8
class 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 '/'
  end
end

 
routes/main.rb

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

 
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
查看更多
小情绪 Triste *
6楼-- · 2019-01-03 07:57

Reading the docs here:

Sinatra Extensions

It appears that Sinatra allows you to decompose your application into Ruby Modules, which can be pulled in through the Sinatra "register" method or "helpers" methods, like so:

helpers.rb

require 'sinatra/base'

module Sinatra
  module Sample
    module Helpers

      def require_logged_in()
        redirect('/login') unless session[:authenticated]
      end

    end
  end
end

routing/foos.rb

require 'sinatra/base'

module Sinatra
  module Sample
    module Routing
      module Foos

        def self.registered(app)           
          app.get '/foos/:id' do
            # invoke a helper
            require_logged_in

            # load a foo, or whatever
            erb :foos_view, :locals => { :foo => some_loaded_foo }
          end   
        end  

      end
    end     
  end
end

app.rb

#!/usr/bin/env ruby

require 'sinatra'

require_relative 'routing/foos'

class SampleApp < Sinatra::Base

  helpers Sinatra::Sample::Helpers

  register Sinatra::Sample::Routing::Foos

end
查看更多
做自己的国王
7楼-- · 2019-01-03 07:58

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

查看更多
登录 后发表回答