Birden fazla dosya aracılığıyla daha büyük projeler için Sinatra'yı kullanma


184

Sinatra'da tüm rota işleyicileri tek bir dosyaya yazılıyor gibi görünüyor, eğer doğru anlıyorsam büyük / küçük bir denetleyici gibi davranıyor. Ayrı bağımsız dosyalara bölmenin herhangi bir yolu var mı, yani diyelim ki birisi "/" çağırdığında - bir eylem yürütülür ve "/ posts / 2" gibi bir smth alınırsa başka bir eylem - PHP'de uygulanan benzer mantık ?

Yanıtlar:


394

İşte kullandığım Sinatra uygulamaları için temel bir şablon. (Daha büyük uygulamalarımda 200'den fazla dosya var, satıcı mücevherleri sayılmıyor, 75-100 açık rotayı kapsıyor. Bu rotalardan bazıları ek 50+ rota düzenini kapsayan Regexp rotalarıdır.) Thin kullanırken, kullanarak böyle bir uygulama:
thin -R config.ru start

Düzenleme : Şimdi Riblits adlı aşağıdaki dayalı kendi Monk iskeleti koruyorum . Şablonumu kendi projelerinizin temeli olarak kopyalamak için kullanmak için:

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

# Inside your empty project directory
monk init -s riblits

Dosya Düzeni:

config.ru
app.rb
yardımcıları /
  init.rb
  partials.rb
modeller /
  init.rb
  user.rb
yolları /
  init.rb
  login.rb
  main.rb
Görüntüleme/
  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'

 
yardımcıları / init.rb

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

require_relative 'nicebytes'
MyApp.helpers NiceBytes

 
yardımcıları / 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

 
yardımcıları / 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

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

 
Modeller / user.rb

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

 
rotalar / init.rb

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

 
rotalar / 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

 
rotalar / main.rb

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

 
görüntüleme / 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

11
Yukarıdaki yapı hakkında özellikle güzel bir şey - özellikle tüm dosyaları koymak require "sequel"ve DBbaşlatmak models/init.rbve kullanmak require_relativeiçin - modelsdizininize cd atabilir , bir IRB konsolu açıp yazabilir require './init've etkileşimli keşif için tam veritabanı ve model kurulumunuzu yükleyebilirsiniz. .
Phrogz

1
Harika bir örnek yapı, benim gibi bir Sinatra çaylakı için mükemmel, şerefe.
Barry Jordan

27
Farklı bir yaklaşım kullandım. Kullanıcılar ve hizmetler gibi tüm iş mantığını, 'sinatra' gerektirmeden kodlayın. Bu, mantığın kendi başına durmasını sağlar. Daha sonra çeşitli sınıflara sorumlulukları ortaya çıkarmak için tek bir uygulama dosyası kullanıyorum, bu yüzden rota başına yaklaşık 3 satır kod. Tipik uygulamada çok fazla rota yok, bu yüzden uygulama dosyam aslında o kadar uzun değil.
Tom Andersen

1
Bir sınıfı birden çok dosyada tanımlamak yaygın bir uygulama mıdır? Her dosyada 'Uygulamam'ı tekrar tekrar tanımlıyorsunuz. Yakutta yeniyim, bu yüzden bana garip geliyor. Bunun arkasındaki sebep nedir?
0xSina

5
@ 0xSina Ruby'de nadir değildir. Bir sınıfı "tanımlamaz", "yeniden açarsınız". Örneğin, Arraysınıf çekirdek kitaplık tarafından tanımlanır, ancak daha sonra "monkeypatch" komutunu kullanarak kullanabilirsiniz class Array; def some_awesome_method; endve a) önceki tüm Dizi işlevleri korunur ve b) tüm Dizi örnekleri yeni kodunuzu alır. Ruby'deki sınıflar sadece nesnelerdir ve her zaman artırılabilir ve değiştirilebilir.
Phrogz

10

Kesinlikle. Bunun bir örneğini görmek için burada açıklanan Keşiş mücevher indirmenizi öneririz:

https://github.com/monkrb/monk

Rubygems.org üzerinden `` gem install '' yapabilirsiniz. Mücevher aldıktan sonra, yukarıda verilen talimatları kullanarak örnek bir uygulama oluşturun.

İstediğiniz sürece gerçek gelişiminiz için Monk kullanmak zorunda olmadığınızı unutmayın (aslında güncel olmadığını düşünüyorum). Burada önemli olan nokta, uygulamanızı MVC stilinde (ayrı denetleyici benzeri rota dosyalarıyla) nasıl kolayca yapılandırabileceğinizi görmek.

Monk'un bunu nasıl ele aldığına bakarsanız, çoğunlukla ayrı dizinlerde dosya gerektirme meselesine bakarsanız, oldukça basittir (root_path tanımlamanız gerekir):

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

7
init.rbYukarıdakilere karşı açık bir şekilde kullanma hakkında güzel bir şey , birbirine bağlı dosyalar olması durumunda yükleme sırasını kontrol edebilmenizdir.
Phrogz

10

Başkalarının Sinatra uygulamalarını nasıl düzenledikleri hakkında fikir edinmek için Google'da "Sinatra ortak levha" araması yapın. Ondan muhtemelen ihtiyaçlarınızı karşılayan birini bulabilir veya sadece kendinizinkini yapabilirsiniz. Bunu yapmak çok zor değil. Daha fazla Sinatra uygulaması geliştirdikçe, kaynak plakasına ekleyebilirsiniz.

Tüm projelerim için yaptığım ve kullandığım şeyler:

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


7

Bu eski bir sorgu olduğunu biliyorum ama hala inanıyorum kimse Padrino Sinatra üstünde bir çerçeve olarak kullanabilirsiniz, ya da parçalı sadece ilginizi çeken taşlar ekleyerek. Bu kıç on buttloads başladı!


Katılıyorum, Padrino'ya bir göz atmalısın, sallanır!
NicoPaez

2

Aynı sitede farklı projelere ev sahipliği yapma yaklaşımım şu şekilde kullanmaktır sinatra/namespace:

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

Kullandığım alt projelerle ilgili başka bir ayrıntı, "/"bir kılavuz ana sayfası yapmak için kullanılan bir tür küresel değişkene isimlerini, açıklamalarını ve rotalarını eklemekti , ancak şu anda bir parçacığım yok.


1

Belgeleri burada okumak:

Sinatra Eklentileri

Sinatra, uygulamanızı Sinatra "kayıt" yönteminden veya "yardımcılar" yöntemlerinden içeri çekilebilen Ruby Modüllerine ayırmanıza izin veriyor gibi görünüyor:

helpers.rb

require 'sinatra/base'

module Sinatra
  module Sample
    module Helpers

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

    end
  end
end

yönlendirme / 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

Monk benim için çalışmadığında, şablonlar üzerinde kendim çalışmaya başladım.

Bunu düşünürseniz, bir dizi dosyayı bağlama konusunda özel bir şey yoktur. Keşiş felsefesi bana 2011'in başlarında RedDotRubyConf sırasında açıklanmıştı ve özellikle özellikle zorlukla bakıldığında bunu kullanmanın gerçekten isteğe bağlı olduğunu söylediler.

Bu, ActiveRecord'u kullanmak isteyenler için iyi bir başlangıçtır:

Basit Sinatra MVC

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


1

Daha büyük projeler için Sinatra'da modülerliğin anahtarı, temel araçları kullanmayı öğrenmektir.

SitePoint, modüler Sinatra uygulamalarını ve yardımcılarını görebileceğiniz çok iyi bir öğreticiye sahiptir . Ancak, önemli bir ayrıntıya özellikle dikkat etmelisiniz. Birden Sinatra uygulamaları korumak ve montaj Rackup onları. Temel bir uygulamanın nasıl yazıldığını öğrendikten sonra, bu öğreticinin config.ru dosyasına bakın ve bağımsız Sinatra uygulamalarını nasıl monte ettiklerini gözlemleyin.

Rack ile Sinatra'yı çalıştırmayı öğrendiğinizde tamamen yeni bir modülerlik dünyası dünyası açılacak. Bu kesinlikle yararlı bir şey denemeye davet ediyor: artık her bir alt uygulama için ayrı Taşlara sahip olmanıza güvenebilirsiniz , bu da modüllerinizi kolayca sürümlendirmenize izin verebilir.

Uygulamanız için gem modülleri kullanmanın gücünü hafife almayın. Deneysel değişiklikleri iyi sınırlandırılmış bir ortamda kolayca test edebilir ve kolayca dağıtabilirsiniz. Bir şeyler ters giderse geri dönmek de aynı derecede kolaydır.

Kodunuzu düzenlemenin bin yolu vardır, bu nedenle Rails'e benzer bir düzen elde etmeye çalışmak zarar vermez. Bununla birlikte , kendi yapınızı nasıl özelleştirebileceğinizle ilgili bazı harika gönderiler de var . Bu yazı, çoğu web geliştiricisinin diğer sık ​​ihtiyaçlarını karşılar.

Zamanınız varsa, Ruby tabanlı herhangi bir web uygulamasının ortak zemini olan Rack hakkında daha fazla bilgi edinmenizi öneririm. İşinizi nasıl yaptığınız üzerinde çok daha az etkisi olabilir, ancak çoğu insanın uygulamalarında bir Rack ara katman yazılımı olarak daha iyi uyan belirli görevler vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.