今回は以下を検討します。
- 重複するファイル名の問題
- ロード前のページ待機
- SASSを使用したCSSの作成
- 認証
- 薄い下から走る
- RSpecを使用したテスト
- ベンチマーク
同じファイル名
前回、 Kaneはアプリケーションの重要なエラーに気付きました。ファイルをダウンロードするための鍵は、そのためのダイジェストです-しかし、同じ名前の2つのファイルをアップロードするとどうなりますか? 残念ながら、それらのダイジェストは一致するため、現在のバージョンでは、どのファイルがユーザーに提供されるか(1つ目または2つ目)を判断することすらできません。 しかし、幸いなことに、このエラーは簡単に修正できます。ダウンロードするファイルのIDをダウンロードリンクに追加するだけです。 したがって、2つの同一ファイルには、次の形式の異なるリンクがあります。
/ダイジェスト/ ID1 /ダイジェスト/ ID2
ただし、ユーザーは他のファイルをダウンロードするためのリンクを決定することはできません(同じファイルをダウンロードするために同じダイジェストのIDを反復処理することしかできません)。 この修正では、init.rbのコードとlist.hamlテンプレートをかなり変更する必要があります。
init.rb :
get '/:sha /:id' do @file = StoredFile.first:sha => params [:sha] ,: id => params [:id] #さらに変更なし get '/:sha /:id / delete' do @file = StoredFile.first:sha => params [:sha] ,: id => params [:id] #さらに変更なし
list.haml :
%a {:href => "/#{file.shaasket/#{file.id}" ,: title => file.filename} = file.filename
現在、同名のファイルは私たちを恐れていません!
ロード前の待機ページ
状況を想像してください。あなたの友人が、あなたが撮った写真を彼に送るように頼みます。 ファイルホスティングにドロップして、ファイルホスティングへのリンクを送信すると、ダウンロードを開始します。 次に、タスクを複雑にします。ファイルサイズは20メガバイトで、友人がGPRSに座っています。 当然、ファイルサイズを事前に知っていた場合、高価なトラフィックを節約するためにダウンロードすることはありませんでした。 解決策:ロードする前に表示されるページを作成し、名前とファイルサイズに関する情報を配置します。
init.rbから始めましょう。
get '/:sha /:id' do @file = StoredFile.first:sha => params [:sha] ,: id => params [:id] params [:nowait] == 'true'でない限り haml:ダウンロード 他に @ file.downloads + = 1 @ file.save send_file "./files/#{@file.idasket.upload" ,: filename => @ file.filename ,: type => 'Application / octet-stream' 終わり 終わり
そのため、リンクパラメータで「nowait = true」が渡された場合、ダウンロードが即座に開始されます。そうでない場合は、download.hamlテンプレートのみが表示されます。
そして実際、ここで彼は:
download.haml :
%script {:type => "text / javascript"} nowait = '?nowait = true'; var timeout = true; setTimeout( 'if(timeout){window.location = window.location + nowait;}'、10000); %h1ファイルのダウンロード .info ファイルをダウンロードしようとしています %span.filename> = "#{@file.filename}" サイズ %span.filesize = @ file.filesize / 1024 キロバイト。 内でダウンロードが開始されます %スパン#秒10 秒。 クリックしてください %a {:href => "/#{params [:sha]}?nowait = true" ,: onclick => 'timeout = false;' }このリンク 待ちたくない場合
最初に、10秒待機して同じリンクにリダイレクトする単純なJavaScriptがありますが、パラメーター「nowait = true」を使用し、ファイル名とサイズを示すテキスト自体を使用します。
ファイルリストテンプレートを展開して、2つのリンクが含まれるようにします-即時ダウンロード(私たちはそれを自分で使用します)と遅延ダウンロード(ICQを介してこのリンクを送信します)。 次のようになります。
list.haml :
%td.filename %a {:href => "/#{file.shaasket/#{file.idasket?nowait=true" ,: title => file.filename} = file.filename = "(#{file.filesize / 1024} Kb)" %a {:href => "/#{file.shaasket/#{file.id}"}転送用
チェックを入れて、次の項目に進みます。
サス
SASSは、CSSファイルの作成を担当するHamlパッケージの一部です。 構文の観点から見ると、SASSはCSSとHamlの間にあります。セレクタと属性(CSS)を含むスキームを使用しますが、リミッターとして中括弧ではなくインデント(Haml)を使用します。
SASSファイルは、一連のルールで構成されています。
セレクター(S) :PROPERTY1 VALUE1 :PROPERTY2 VALUE2 ... :PROPERTY_N VALUE_N
SELECTOR(S)は1つ以上の通常のCSSセレクター(クラス、ID、タグ名)であり、PROPRETY_X / VALUE_XはCSSプロパティの名前と値です。 CSSに非常に似ていますが、いくつかの違いがあります。
- 中括弧の代わりに、2つのスペースのインデントが使用されます
- ネストされたルールを使用できます(CSSルールの複雑なセットには便利です):
#main p :色#00ff00 :幅97% .redbox :背景色#ff0000 :色#000000
にコンパイルする#main p { 色:#00ff00; 幅:97%; } #main p .redbox { 背景色:#ff0000; 色:#000000; }
- ネストされた「名前空間」:
.funky :フォント :家族のファンタジー :サイズ30em :太字の太さ
コンパイル済み.funky { フォントファミリー:ファンタジー; フォントサイズ:30em; フォントの太さ:太字。 }
- 定数と算術演算の使用:
!main_width = 10 !unit1 = em !unit2 = px !bg_color =#a5f39e #メイン :背景色=!bg_color p :背景色=!bg_color +#202020 :幅=!main_width +!unit1 img.thumb :幅=(!main_width + 15)+!unit2
- SASSコメント-SASSテンプレートには存在しますが、最終的なCSSにはありません
- 最終的なCSSをフォーマットするためのいくつかのオプション(最大限に読み取り可能な展開から最小限の圧縮まで)
しかし、ラムに戻ります。SASSファイルは2つの方法で使用できます。CSSファイルを取得してアプリケーションに接続するか、Sinatraに組み込まれたSASSテンプレートエンジンを使用してCSSを「オンザフライ」で生成できます。 無意味にもかかわらず、2番目の方法を使用します:)
init.rb :
'/style.css'を取得します response ['Content-Type'] = 'text / css; charset = utf-8 '#応答ヘッダーを設定します sass:スタイル 終わり
layout.haml :
%link {:href => "/style.css" ,: media => "screen" ,: rel => "stylesheet" ,: type => "text / css"}
さて、あなたはこのリンクで私のstyle.sassファイルを見ることができます。
これで、アプリケーションにある種のデザインができました。
認証
それでは、通常の認証メカニズムをアプリケーションに添付します。 誰もが直接リンクを介してファイルをダウンロードできるようにしたいのですが、アップロードとファイルの削除、および一般リストの表示は、パスワードを入力した後にのみ使用可能にする必要があります(簡単にするため、ハードコードされたパスワードを1つ設定します)。
この問題を次のように解決しました。HTTP認証モジュール( 参照によるコード)を取得し、libフォルダーに配置して、init.rbに次の変更を加えました。
「lib /承認」が必要 ヘルパーは Sinatraを含める::認証 終わり 「/」を取得 require_administrative_privileges #次に変更なし 終わり 「/」を投稿 require_administrative_privileges #投稿は変更なし 終わり get '/:sha /:id / delete' do require_administrative_privileges #変更せずにさらに削除 終わり
要するに、「helpers do ... end」ブロックはすべてのブロックのコンテキストで実行されます-URLハンドラー、つまり、アプリケーション内でSinatra:Authorizationモジュールを使用可能にします。 同じブロック内で、テンプレートとメインアプリケーションで使用できるメソッドを定義できます(いわゆるヘルパーは、テンプレート内で同じコードを繰り返さないようにするヘルパーメソッドです)。
薄い下から走る
そのため、私たちのアプリケーションは産業の高みに達し、本番サーバーに展開する準備ができています。 ruby init.rbコマンドで実行し、rubyを備えたコンソールが開いているときに動作することを思い出させてください-もちろん、これは深刻ではありません-WebアプリケーションはWebサーバーによって起動されるべきです。 Webサーバーとしては、 Thinを選択します。これは、Rubyアプリケーション用のコンパクトで非常に高速なサーバーです。 インストールは簡単です:
sudo gem install thin
ここで、アプリケーションのディレクトリにいくつかのフォルダーを作成します。
mkdir config mkdir tmp mkdirログ
configフォルダーで、config.rbファイルをlibフォルダーから移動します(同時に、init.rbでファイルへのパスを修正します)。 thinを設定するには、thin.ymlを呼び出すファイルが必要です-configフォルダーに作成し、以下を記述します:
--- 環境:生産 chdir:アプリケーションカタログ pid:アプリケーションカタログ/ tmp / thin.pid rackup:アプリケーションカタログ/ config / config.ru log:アプリケーションカタログ/ log / thin.log max_conns:1024 タイムアウト:30 max_persistent_conns:512 daemonize:true
アプリケーションのルートディレクトリにchdirを作成し、tmpフォルダーにPIDファイルを配置し、configフォルダーにRackupファイル(以下について)を作成し、log / log 30秒のタイムアウトで最大1024の同時接続、最大512の永続的な接続を維持し、デーモンとして動作します(つまり、システムにログインしているユーザーの存在に関係なく)。
ラックアップファイルについて:実際、これはRubyとWebサーバー間のラックインターフェースの構成ファイルです(この例では薄い)。 このファイルには2行のみが含まれています。
「init」が必要 ラック::ハンドラー:: Thin.run Sinatra :: Application ,: Port => 3000 ,: Host => "0.0.0.0"
最初の行はinit.rb(つまり、アプリケーション)を接続し、2行目は3000番目のポートでシンを実行してSinatraアプリケーションを渡す必要があることをRackに伝えます。
仕事は完了です! このコマンドでアプリケーションが起動します
シンスタート-C config / thin.yml
設定ファイルをシンに渡すだけです。
コマンドによる停止
シンストップ-C config / thin.yml
RSpecを使用したテスト
Sinatraのアプリケーションをテストする人はほとんどいないことを理解しているため、最後に特別にこのセクションを終了しました。 詳細には触れず、 RSpecがどのようなものであるかを説明せず、仕様がどのように見えるかを示します。
「シナトラ」が必要 「シナトラ/テスト/ rspec」が必要 「init」が必要 「TrashFilesアプリ」の説明 「遅延してテンプレートをレンダリングする」必要があります @file = StoredFile.first get "/#{@file.shaasket/#{@file.id}" @response ['Content-Type']。should == "text / html" 終わり 「ファイルを提供する必要がありますか?nowait = trueが指定されている場合」 @file = StoredFile.first get "/#{@file.shaasket/#{@file.idasket?nowait=true" @response ['Content-Type']。should == "Application / octet-stream" @response ['Content-Disposition']。should == "attachment; filename = \"#{@ file.filename} \ "" 終わり 終わり
トリックはありません-たとえば、Railsの場合と同じ/ it / shouldを記述します。 主なことは、シナトラ/テスト/ rspecを接続することを忘れないことです。
ベンチマーク
コメントの1つで、結果のアプリケーションのパフォーマンスを測定するように依頼されました-問題ありません。最初-メインページ(ファイルのリスト)のベンチマーク。
ab -n 1000 -c 1 -A admin:secret http://127.0.0.1 {000 /
同時実行レベル:1 テストにかかった時間:24.109秒 転送された合計:3,739,000バイト 転送されるHTML:3604000バイト 1秒あたりのリクエスト:41.48 [#/秒](平均) リクエストあたりの時間:24.109 [ms](平均) リクエストあたりの時間:24.109 [ms](平均、すべての同時リクエスト全体) 転送速度:151.45 [Kバイト/秒]受信
ab -n 1000 -c 10 -A admin:secret http://127.0.0.1∗000/
同時実行レベル:10 テストにかかった時間:24.381秒 転送された合計:3,739,000バイト 転送されるHTML:3604000バイト 1秒あたりのリクエスト:41.02 [#/秒](平均) リクエストあたりの時間:243.811 [ms](平均) リクエストあたりの時間:24.381 [ms](平均、すべての同時リクエスト全体) 転送速度:149.76 [Kバイト/秒]受信
ab -n 1000 -c 100 -A admin:secret http://127.0.0.1 {000 /
同時実行レベル:100 テストにかかった時間:23.798秒 転送された合計:3,739,000バイト 転送されるHTML:3604000バイト 1秒あたりのリクエスト:42.02 [#/秒](平均) リクエストあたりの時間:2379.816 [ms](平均) リクエストあたりの時間:23.798 [ms](平均、すべての同時リクエスト全体) 転送速度:153.43 [Kバイト/秒]受信
サーバーへのファイルのアップロード(ファイルサイズ1.5 Kb)
ab -n 1000 -c 1 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /
同時実行レベル:1 テストにかかった時間:16.305秒 転送された合計:160000バイト 投稿された合計:242000 1秒あたりのリクエスト:61.33 [#/秒](平均) リクエストあたりの時間:16.305 [ms](平均) リクエストあたりの時間:16.305 [ms](平均、すべての同時リクエスト全体) 転送速度:9.58 [キロバイト/秒]受信 14.49 kb / s送信 合計24.08 kb / s
ab -n 1000 -c 10 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /
同時実行レベル:10 テストにかかった時間:18.463秒 転送された合計:161280バイト 投稿された合計:243936 転送されたHTML:0バイト 1秒あたりのリクエスト:54.16 [#/ sec](平均) リクエストあたりの時間:184.631 [ms](平均) リクエストあたりの時間:18.463 [ms](平均、すべての同時リクエスト全体) 転送速度:8.53 [キロバイト/秒]受信 12.90 kb / s送信 合計21.43 kb / s
ab -n 1000 -c 100 -A admin:secret -T 'application / x-www-form-urlencoded' -p post.data http://127.0.0.1 {000 /
同時実行レベル:100 テストにかかった時間:16.029秒 転送された合計:160160バイト 投稿された合計:242242 転送されたHTML:0バイト 1秒あたりのリクエスト:62.39 [#/秒](平均) リクエストあたりの時間:1602.899 [ms](平均) リクエストあたりの時間:16.029 [ms](平均、すべての同時リクエスト全体) 転送速度:9.76 [キロバイト/秒]受信 14.76 kb / s送信 合計24.52 kb / s
同時要求の数が100(100!)回増加しても、パフォーマンスはあまり変化しないことに注意してください。 テストは、Mac Book Core 2 Duo 2.4 Ghz、2 GB RAMで実行され、いくつかのアプリケーションがバックグラウンドで実行されました。
終わり
私の偶然に始まった物語を完了する時が来ました。 興味を持っていただければ幸いであり、少なくとも一部の人が非主流の技術(Sinatra、DataMapper、thin、haml、sass)の研究を奨励できたと思います。 最新バージョンのアプリケーションはgithubに投稿されています。 これらのかなり大きな記事を読んでくれたすべての人に感謝します。