複数のファイルを介してSinatraを使用して大きなプロジェクトを作成する


184

シナトラでは、すべてのルートハンドラーが1つのファイルに書き込まれているようです。それを別々の独立したファイルに分割する方法はありますか?誰かが「/」を呼び出したとしましょう-1つのアクションが実行され、「/ posts / 2」のようなsmthが受信された場合、別のアクション-PHPに適用される同様のロジック?

回答:


394

以下は、私が使用するSinatraアプリの基本テンプレートです。(私の大きなアプリでは、このように分解された200以上のファイルがあり、ベンダーの宝石を数えず、75-100の明示的なルートをカバーしています。これらのルートの一部は、追加の50+ルートパターンをカバーするRegexpルートです。)Thinを使用する場合、このようなアプリを使用して:
thin -R config.ru start

編集:以下のRiblitsに基づいて、自分のモンクのスケルトンを維持しています。自分のプロジェクトのベースとしてテンプレートをコピーするために使用するには:

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

# Inside your empty project directory
monk init -s riblits

ファイルレイアウト:

config.ru
app.rb
ヘルパー/
  init.rb
  partials.rb
モデル/
  init.rb
  user.rb
ルート/
  init.rb
  login.rb
  main.rb
ビュー/
  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

 
ルート/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

 
ルート/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

11
上記の構造、特にrequire "sequel"でのDB初期化models/init.rbrequire_relativeすべてのファイルの初期化で特に優れている点の1つは、modelsディレクトリにcdし、IRBコンソールを開いて入力するrequire './init'と、インタラクティブな探索のためにデータベースとモデルのセットアップ全体が読み込まれることです。 。
Phrogz

1
私のようなシナトラの初心者にぴったりの素晴らしい例の構造、乾杯。
バリージョーダン

27
私は別のアプローチを使用しました。ユーザーやサービスなどのすべてのビジネスロジックをルビでコーディングします。「シナトラ」は必要ありません。これにより、ロジックが独立します。次に、1つのアプリファイルを使用してさまざまなクラスに責任を負わせるので、ルートごとに約3行のコードを実行します。一般的なアプリケーションには多くのルートがないため、実際のアプリファイルはそれほど長くありません。
トムアンデルセン

1
複数のファイルでクラスを定義することは一般的な方法ですか?すべてのファイルで「MyApp」を何度も再定義しています。私はルビーが初めてなので、奇妙に思えます。この背後にある理由は何ですか?
0xSina 2013

5
@ 0xSina Rubyでは珍しいことではありません。クラスを「定義」するのではなく、「再開」します。たとえば、Arrayクラスはコアライブラリによって定義されますが、後で「monkeypatch」を使用してclass Array; def some_awesome_method; end、a)以前のすべての配列機能を保持し、b)すべての配列インスタンスで新しいコードを取得できます。Rubyのクラスは単なるオブジェクトであり、いつでも拡張および変更できます。
Phrogz 2013

10

もちろんです。この例を確認するには、ここで説明するMonk gemをダウンロードすることをお勧めします。

https://github.com/monkrb/monk

rubygems.orgから「gemインストール」できます。Gemを入手したら、上記のリンク先の手順を使用してサンプルアプリを生成します。

必要がない限り、実際の開発にMonkを使用する必要がないことに注意してください(実際、最新ではない可能性があります)。重要なのは、必要に応じて、アプリをMVCスタイル(コントローラーのような個別のルートファイルを使用)で簡単に構成できることを確認することです。

Monkがそれをどのように処理するかを見ると、ほとんどの場合、(root_pathを定義する必要があります)次のような別のディレクトリにあるファイルを要求するという問題です。

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

7
init.rb上記と比較して明示的に使用することの良い点の1つは、相互に依存するファイルがある場合に、読み込みの順序を制御できることです。
Phrogz

10

「Sinatraボイラープレート」でGoogle検索を実行して、他の人がSinatraアプリケーションをどのようにレイアウトしているかについてのアイデアを入手してください。それから、おそらくあなたのニーズに合ったものを見つけるか、単に自分で作ることができます。難しいことではありません。Sinatraアプリをさらに開発するにつれ、定型に追加できます。

これが私が作成し、すべてのプロジェクトで使用したものです。

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


7

私は、これは古いクエリです知っているが、私はまだ誰も言及していないと信じてすることはできませんPadrinoのあなたはシナトラの上のフレームワークとしてそれを使用することができ、あるいは断片的なあなただけの宝石その興味を追加します。お尻の尻を10回蹴る!


私は同意します、あなたはパドリーノを見てみるべきです、それは素晴らしいです!
NicoPaez

2

同じサイトでさまざまなプロジェクトをホストする私のアプローチは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
    ...

私が使用したサブプロジェクトに関するもう1つの詳細は"/"、ガイドのホームページを作成するために使用される、ある種のグローバル変数にそれらの名前、説明、ルートを追加することでしたが、現在のところスニペットはありません。


1

ここでドキュメントを読む:

シナトラ拡張

Sinatraでは、アプリケーションをRubyモジュールに分解できるようです。Rubyモジュールは、次のように、Sinatraの「登録」メソッドまたは「ヘルパー」メソッドを通じて取得できます。

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

1

モンクがうまくいかなかったとき、私は自分でテンプレートの作業を始めました。

考えてみれば、ファイルのセットを拘束することについて特別なことは何もありません。修道士の哲学は、2011年の初めにRedDotRubyConfの間に説明され、特にメンテナンスがほとんど行われていないため、このオプションを使用することは本当にオプションであると具体的に言われました。

これは、ActiveRecordを使用したい人にとって良いスタートです:

シンプルシナトラMVC

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


1

大規模なプロジェクトのためのシナトラのモジュール性の鍵は、基礎となるツールの使用法を学ぶことです。

SitePointには、モジュール式のSinatraアプリとヘルパーを見ることができる非常に優れたチュートリアルがあります。ただし、1つの重要な詳細には特別な注意を払う必要があります。複数のSinatraアプリを保持し、それらをRackupでマウントします。基本的なアプリの作成方法がわかったら、そのチュートリアルのconfig.ruファイルを見て、独立したSinatraアプリをどのようにマウントするかを観察します。

RackでSinatraを実行する方法を学ぶと、モジュール化戦略のまったく新しい世界が開かれます。これは明らかに、本当に便利なものを試すことを勧めます。これで、サブアプリケーションごとに個別のGemを使用できるようになり、モジュールを簡単にバージョン管理できるようになります。

アプリでgem-modulesを使用する力を過小評価しないでください。区切られた環境で実験的な変更を簡単にテストし、簡単に展開できます。何か問題が発生した場合にも、簡単に元に戻すことができます。

コードを整理する方法は1000通りあるので、Railsのようなレイアウトを取得しようとしても支障はありません。ただし、独自の構造をカスタマイズする方法についてのすばらしい記事もあります。その投稿は、ほとんどのWeb開発者のその他の頻繁なニーズをカバーしています。

時間があれば、RubyベースのWebアプリケーションの共通基盤であるRackについて詳しく学ぶことをお勧めします。作業方法への影響ははるかに小さいかもしれませんが、ほとんどの人がアプリで実行する特定のタスクが常にあり、Rackミドルウェアとして適しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.