Uso de Sinatra para proyectos más grandes a través de varios archivos


Parece que en Sinatra todos los controladores de ruta se escriben en un solo archivo, si entiendo bien actúa como un controlador grande/pequeño. ¿Hay alguna manera de dividirlo en archivos independientes separados, así que cuando digamos que alguien llama a "/" - se ejecuta una acción, y si se recibe smth como "/posts/2" entonces se aplica otra acción - lógica similar en PHP?

 182
Author: Phrogz, 2011-02-16

8 answers

Aquí hay una plantilla básica para las aplicaciones de Sinatra que uso. (Mis aplicaciones más grandes tienen más de 200 archivos rotos de esta manera, sin contar las gemas vendor'd, que cubren 75-100 rutas explícitas. Algunas de estas rutas son rutas Regexp que cubren más de 50 patrones de ruta adicionales.) Al usar Thin, ejecuta una aplicación como esta usando:
thin -R config.ru start

Edit : Ahora estoy manteniendo mi propio esqueleto Monk basado en el siguiente llamado Riblits. Para usarlo para copiar mi plantilla como la base para sus propios proyectos:

# Before creating your project
monk add riblits git://github.com/Phrogz/riblits.git

# Inside your empty project directory
monk init -s riblits

Archivo Diseño:

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


ayudantes/parciales.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


modelos / 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'


modelos/usuario.rb

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


rutas / init.rb

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


rutas/inicio de sesión.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


rutas / main.rb

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


vistas/diseño.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
 389
Author: Phrogz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-22 12:51:06

Absolutamente. Para ver un ejemplo de esto recomiendo descargar la gema Monk, descrita aquí:

Https://github.com/monkrb/monk

Puede 'instalar gema' a través de rubygems.org.Una vez que tenga la gema, genere una aplicación de ejemplo utilizando las instrucciones enlazadas anteriormente.

Tenga en cuenta que no tiene que usar Monk para su desarrollo real a menos que lo desee (de hecho, creo que puede no ser actual). El punto es ver cómo puede estructurar fácilmente su aplicación en el estilo MVC (con archivos de ruta separados similares al controlador) si lo desea.

Es bastante simple si nos fijamos en cómo Monk lo maneja, principalmente una cuestión de requerir archivos en directorios separados, algo así como (tendrá que definir root_path):

Dir[root_path("app/**/*.rb")].each do |file|
    require file
end
 10
Author: TK-421,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-16 14:03:06

Haga una búsqueda en Google de "Sinatra boilerplate" para obtener algunas ideas sobre cómo otros están diseñando sus aplicaciones Sinatra. A partir de eso, probablemente pueda encontrar uno que se adapte a sus necesidades o simplemente hacer el suyo propio. No es muy difícil de hacer. A medida que desarrolles más aplicaciones Sinatra, puedes agregarlas a tu plantilla.

Esto es lo que hice y utilicé para todos mis proyectos:

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

 10
Author: Robert Ziehl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-18 05:02:58

Sé que esta es una consulta antigua, pero todavía no puedo creer que nadie mencionó Padrino Puede usarlo como un marco sobre Sinatra, o por partes agregando solo las gemas que le interesen. ¡Patea diez culos!

 7
Author: Steven Garcia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-27 21:52:30

Mi enfoque para alojar diferentes proyectos en el mismo sitio es usar sinatra/namespace de tal manera:

Servidor.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
    ...

Otro detalle sobre los subproyectos que utilicé fue agregar sus nombres, descripción y rutas a algún tipo de variable global, que es utilizada por "/" para hacer una página de inicio de guía, pero no tengo un fragmento en este momento.

 2
Author: Nakilon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-17 14:45:20

Leyendo los documentos aquí:

Extensiones de Sinatra

Parece que Sinatra le permite descomponer su aplicación en módulos Ruby, que se pueden extraer a través del método "register" o métodos "helpers" de Sinatra, así:

Ayudantes.rb

require 'sinatra/base'

module Sinatra
  module Sample
    module Helpers

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

    end
  end
end

Enrutamiento/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
 1
Author: Erin Swenson-Healey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-03 17:36:32

Cuando Monk no trabajaba para mí, empecé a trabajar en plantillas yo mismo.

Si lo piensas bien, no hay nada especial en vincular un conjunto de archivos. La filosofía monk me fue explicada a principios de 2011 durante RedDotRubyConf y me han dicho específicamente que es realmente opcional usarla, especialmente ahora que apenas se mantiene.

Este es un buen comienzo para aquellos que quieren usar ActiveRecord:

Simple Sinatra MVC

Https://github.com/katgironpe/simple-sinatra-mvc

 1
Author: kgpdeveloper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-23 17:00:59

La clave para la modularidad en Sinatra para proyectos más grandes es aprender a usar las herramientas subyacentes.

SitePoint tiene un muy buen tutorial desde donde se pueden ver aplicaciones modulares de Sinatra y helpers. Sin embargo tenéis que prestar la atención especial a un detalle importante. Mantiene varias aplicaciones Sinatra y las monta con Rackup. Una vez que sepa cómo escribir una aplicación básica, mire config.ru archivo de ese tutorial y observar cómo montan Sinatra independiente aplicaciones.

Una vez que aprendas a ejecutar Sinatra con Rack, se abrirá un nuevo mundo de estrategias de modularidad. Obviamente, esto invita a probar algo realmente útil: ahora puede confiar en tener gemas individuales para cada subaplicación , lo que podría permitirle versionar fácilmente sus módulos.

No subestime el poder de usar módulos de gemas para su aplicación. Puede probar fácilmente los cambios experimentales en un entorno bien delimitado e implementarlos fácilmente. Igualmente fácil de volver atrás si algo sale mal.

Hay mil formas de organizar tu código, por lo que no estaría de más intentar conseguir un diseño similar a Rails. Sin embargo, también hay algunos grandes mensajes acerca de cómo personalizar su propia estructura. Esa publicación cubre otras necesidades frecuentes de la mayoría de los desarrolladores web.

Si tienes tiempo, te animo a aprender más sobre Rack, el terreno común para cualquier aplicación web basada en Ruby. Podría tener un impacto mucho menor en cómo haces tu trabajo, pero siempre hay ciertas tareas que la mayoría de las personas hacen en sus aplicaciones que se ajustan mejor como un middleware de rack.

 1
Author: SystematicFrank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-30 12:37:56