Ruby on Rails (「Rails」)は、人気のあるオープンソースフレームワークです。 ルビー Webアプリケーション開発プロセスの簡素化と合理化に努めるプログラミング言語。
Railsは次の原則に基づいて構築されています 設定より規約 。簡単に言えば、これは、デフォルトで、Railsが エキスパート開発者 は「標準」のベストプラクティス規則(名前付け、コード構造など)に従います。そうすると、これらの詳細を指定しなくても、「自動的に」機能します。このパラダイムには利点がありますが、落とし穴もあります。最も注目すべきは、フレームワークの舞台裏で発生する「魔法」が、ヘッドフェイク、混乱、「一体何が起こっているのか」につながる可能性があることです。問題の種類。また、セキュリティとパフォーマンスに関して望ましくない影響を与える可能性があります。
したがって、Railsは使いやすい一方で、誤用も難しくありません。このチュートリアルでは、Railsの10の一般的な問題について、それらを回避する方法やそれらが引き起こす問題を含めて説明します。
Railsはに基づいています MVCアーキテクチャ 。 Railsコミュニティでは、 ファットモデル、スキニーコントローラー しばらくの間、私が継承した最近のRailsアプリケーションのいくつかは、この原則に違反していました。ビューロジック(ヘルパーに格納する方が適切)、またはドメイン/モデルロジックをコントローラーに移動するのは非常に簡単です。
問題は、コントローラーオブジェクトが違反し始めることです。 単一責任の原則 コードベースに将来の変更を加えることは難しく、エラーが発生しやすくなります。一般的に、 のみ コントローラに必要なロジックのタイプは次のとおりです。
これは依然として単一責任の原則の限界を押し上げますが、Railsフレームワークがコントローラーに必要とする最低限のことです。
すぐに使用できるRailsテンプレートエンジン、 ERB は、可変コンテンツのページを作成するための優れた方法です。ただし、注意しないと、すぐにHTMLとRubyコードが混在する大きなファイルになってしまい、管理と保守が困難になる可能性があります。これはまた、多くの繰り返しにつながる可能性のある領域であり、違反につながる可能性があります ドライ (繰り返してはいけません)原則。
これは、さまざまな形で現れる可能性があります。 1つは、ビューでの条件付きロジックの乱用です。簡単な例として、current_user
がある場合を考えてみましょう。現在ログインしているユーザーを返す使用可能なメソッド。多くの場合、ビューファイルには次のような条件付きロジック構造があります。
Welcome, Guest
このようなものを処理するためのより良い方法は、オブジェクトがcurrent_user
によって返されることを確認することです。です 常に 誰かがログインしているかどうかに関係なく、ビューで使用されているメソッドに適切な方法で応答するように設定します(nullオブジェクトと呼ばれることもあります)。たとえば、current_user
を定義できます。 app/controllers/application_controller
のヘルパーこのような:
require 'ostruct' helper_method :current_user def current_user @current_user ||= User.find session[:user_id] if session[:user_id] if @current_user @current_user else OpenStruct.new(name: 'Guest') end end
これにより、前のビューコード例を次の1行の単純なコードに置き換えることができます。
Welcome,
Railsの推奨される追加のベストプラクティスがいくつかあります。
ビューとコントローラーのロジックを最小化するためのガイダンスを考えると、 MVCアーキテクチャ そのすべてのロジックをモデルに含めることでしょ?
まあ、完全ではありません。
たくさんの Rails開発者 実際にこの間違いを犯して、すべてを彼らのActiveRecord
に貼り付けてしまうことになります単一責任の原則に違反するだけでなく、メンテナンスの悪夢でもあるmongoファイルにつながるモデルクラス。
メール通知の生成、外部サービスへのインターフェース、他のデータ形式への変換などの機能は、ActiveRecord
の中心的な責任とはあまり関係がありません。データベース内のデータを見つけて永続化するだけのモデル。
では、ロジックをビューに配置したり、コントローラーに配置したり、モデルに配置したりしない場合は、どこに配置する必要がありますか?
入る プレーンな古いRubyオブジェクト (ポロス)。 Railsのような包括的なフレームワークでは、新しい開発者はフレームワークの外部で独自のクラスを作成することをためらうことがよくあります。ただし、ロジックをモデルからPOROに移動することは、多くの場合、過度に複雑なモデルを回避するために医師が命じたものです。 POROを使用すると、メール通知やAPIインタラクションなどを、ActiveRecord
に固定するのではなく、独自のクラスにカプセル化できます。モデル。
次のうち、トークンベースの認証の例はどれですか?
したがって、それを念頭に置いて、一般的に言えば、モデルに残しておく必要がある唯一のロジックは次のとおりです。
ActiveRecord
構成 (つまり、関係と検証)full_name
フィールドとfirst_name
フィールドを組み合わせるlast_name
メソッド)find
よりも複雑です);一般的に言って、where
は絶対に使用しないでください。モデルクラス自体の外部にあるメソッド、またはそのような他のクエリ構築メソッドこの間違いは、上記の間違い#3の当然の結果です。説明したように、Railsフレームワークは、MVCフレームワークの名前付きコンポーネント(モデル、ビュー、コントローラーなど)に重点を置いています。これらの各コンポーネントのクラスに属するものの種類についてはかなり良い定義がありますが、3つのいずれにも当てはまらないように見えるメソッドが必要になる場合があります。
Railsジェネレーターは、作成する新しいリソースごとに、ヘルパーディレクトリと新しいヘルパークラスを便利に構築します。ただし、モデル、ビュー、またはコントローラーに正式に適合しない機能をこれらのヘルパークラスに詰め込み始めるのは非常に魅力的です。
Railsは確かにMVC中心ですが、独自のタイプのクラスを作成し、それらのクラスのコードを保持するための適切なディレクトリを追加することを妨げるものは何もありません。追加の機能がある場合は、どのメソッドがグループ化されるかを考え、それらのメソッドを保持するクラスの適切な名前を見つけます。 Railsのような包括的なフレームワークを使用することは、優れたオブジェクト指向設計のベストプラクティスを邪魔する言い訳にはなりません。
RubyとRailsは 宝石の豊かな生態系 これは、開発者が考えることができるほぼすべての機能を集合的に提供します。これは、複雑なアプリケーションをすばやく構築するのに最適ですが、アプリケーションの宝石の数がGemfile
である肥大化したアプリケーションも数多く見ました。提供される機能と比較すると、不釣り合いに大きいです。
これにより、いくつかのRailsの問題が発生します。宝石を過度に使用すると、Railsプロセスのサイズが必要以上に大きくなります。これにより、本番環境のパフォーマンスが低下する可能性があります。ユーザーの不満に加えて、これにより、より大きなサーバーメモリ構成が必要になり、運用コストが増加する可能性があります。また、大規模なRailsアプリケーションの起動に時間がかかるため、開発が遅くなり、自動テストにかかる時間が長くなります(通常、遅いテストはそれほど頻繁に実行されません)。
アプリケーションに持ち込む各gemは、他のgemに依存している可能性があり、それらは他のgemに依存している可能性があることに注意してください。したがって、他の宝石を追加すると、複合効果が生じる可能性があります。たとえば、 rails_admin
gemは、ベースのRailsインストールから10%以上増加し、合計11個のgemを追加します。
この記事の執筆時点で、Rails 4.1.0の新規インストールでは、Gemfile.lock
に43個のgemが含まれています。ファイル。これは明らかにGemfile
に含まれている以上のものですそして、少数の標準的なRailsgemが依存関係として持ち込むすべてのgemを表します。
各宝石を追加するときに、余分なオーバーヘッドが価値があるかどうかを慎重に検討してください。例として、開発者はしばしば何気なくrails_admin
を追加しますgemは、基本的にモデル構造に優れたWebフロントエンドを提供するためですが、実際には、洗練されたデータベースブラウジングツールにすぎません。アプリケーションに追加の権限を持つ管理者ユーザーが必要な場合でも、生のデータベースアクセスを許可したくない場合は、このgemを追加するよりも、独自のより合理化された管理機能を開発する方がよいでしょう。
ほとんどのRails開発者は、開発中および本番環境で使用可能なデフォルトのログファイルを認識していますが、それらのファイルの情報に十分な注意を払っていないことがよくあります。多くのアプリケーションは次のようなログ監視ツールに依存していますが ラーテル または New Relic 本番環境では、アプリケーションの開発とテストのプロセス全体を通じてログファイルを監視することも重要です。
このチュートリアルで前述したように、Railsフレームワークは、特にモデルにおいて、多くの「魔法」を実行します。モデルで関連付けを定義すると、リレーションを非常に簡単に取得して、ビューですべてを利用できるようになります。モデルオブジェクトを埋めるために必要なすべてのSQLが生成されます。それは素晴らしいことです。しかし、生成されているSQLが効率的であることをどうやって知ることができますか?
よく遭遇する1つの例は、 N +1クエリの問題 。問題はよく理解されていますが、問題が発生していることを確認する唯一の実際の方法は、ログファイル内のSQLクエリを確認することです。
たとえば、一般的なブログアプリケーションで次のクエリがあり、選択した一連の投稿に対するすべてのコメントが表示されているとします。
def comments_for_top_three_posts posts = Post.limit(3) posts.flat_map do |post| post.comments.to_a end end
このメソッドを呼び出すリクエストのログファイルを見ると、次のようなものがあります。3つの投稿オブジェクトを取得するために1つのクエリが実行され、次にそれらの各オブジェクトのコメントを取得するためにさらに3つのクエリが実行されます。
Started GET '/posts/some_comments' for 127.0.0.1 at 2014-05-20 20:05:13 -0700 Processing by PostsController#some_comments as HTML Post Load (0.4ms) SELECT 'posts'.* FROM 'posts' LIMIT 3 Comment Load (5.6ms) ELECT 'comments'.* FROM 'comments' WHERE 'comments'.'post_id' = ? [['post_id', 1]] Comment Load (0.4ms) SELECT 'comments'.* FROM 'comments' WHERE 'comments'.'post_id' = ? [['post_id', 2]] Comment Load (1.5ms) SELECT 'comments'.* FROM 'comments' WHERE 'comments'.'post_id' = ? [['post_id', 3]] Rendered posts/some_comments.html.erb within layouts/application (12.5ms) Completed 200 OK in 581ms (Views: 225.8ms | ActiveRecord: 10.0ms)
ActiveRecord
の 積極的な読み込み Railsの機能により、指定できるようにすることでクエリの数を大幅に減らすことができます あらかじめ ロードされるすべてのアソシエーション。これは、includes
を呼び出すことによって行われます。構築中のArel(preload
)オブジェクトの(またはActiveRecord::Relation
)メソッド。 includes
、ActiveRecord
を使用指定されたすべての関連付けが、可能な限り最小限のクエリを使用してロードされるようにします。例えば。:
def comments_for_top_three_posts posts = Post.includes(:comments).limit(3) posts.flat_map do |post| post.comments.to_a end end
上記の改訂されたコードを実行すると、ログファイルに、すべてのコメントが3つではなく1つのクエリで収集されたことがわかります。
Started GET '/posts/some_comments' for 127.0.0.1 at 2014-05-20 20:05:18 -0700 Processing by PostsController#some_comments as HTML Post Load (0.5ms) SELECT 'posts'.* FROM 'posts' LIMIT 3 Comment Load (4.4ms) SELECT 'comments'.* FROM 'comments' WHERE'comments '.'post_id' IN (1, 2, 3) Rendered posts/some_comments.html.erb within layouts/application (12.2ms) Completed 200 OK in 560ms (Views: 219.3ms | ActiveRecord: 5.0ms)
はるかに効率的です。
N + 1の問題に対するこの解決策は、実際には、十分な注意を払っていない場合にアプリケーションの「内部」に存在する可能性のある非効率性の例としてのみ意図されています。ここでのポイントは、開発中に開発ログファイルとテストログファイルをチェックして、応答を構築するコードの非効率性をチェックする(そして対処する)必要があるということです。
ログファイルを確認することは、コードの非効率性を指摘し、アプリケーションが本番環境に移行する前にそれらを修正するための優れた方法です。そうしないと、開発とテストで使用するデータセットが本番環境よりもはるかに小さい可能性があるため、システムが稼働するまで、結果として生じるRailsのパフォーマンスの問題に気付かない可能性があります。新しいアプリで作業している場合、本番データセットでさえ最初は小さく、アプリは正常に実行されているように見える場合があります。ただし、本番データセットが大きくなると、このようなRailsの問題により、アプリケーションの実行速度が低下します。
ログファイルが不要な情報で詰まっていることがわかった場合 ここに それらをクリーンアップするためにできることがいくつかあります(そこでのテクニックは、開発ログと本番ログで機能します)。
RubyとRailsは、デフォルトで強力な自動テスト機能を提供します。多くのRails開発者は、を使用して非常に洗練されたテストを作成します TDDおよびBDDスタイル のような宝石でさらに強力なテストフレームワークを利用します rspec そして きゅうり 。
Railsアプリケーションに自動テストを追加するのは非常に簡単ですが、文字通りそこに継承または参加したプロジェクトの数に非常に不愉快に驚いています。 番号 以前の開発チームによって作成された(またはせいぜいごくわずかな)テスト。テストをどの程度包括的にすべきかについては多くの議論がありますが、少なくとも いくつか 自動テストは、すべてのアプリケーションに存在する必要があります。
一般的な経験則として、コントローラーのアクションごとに少なくとも1つの高レベルの統合テストを作成する必要があります。将来のある時点で、他のRails開発者はコードを拡張または変更したり、RubyまたはRailsバージョンをアップグレードしたりする可能性が高く、このテストフレームワークは、アプリケーションの基本機能が次のとおりであることを確認する明確な方法を提供します。ワーキング。このアプローチの追加の利点は、将来の開発者に、アプリケーションによって提供される機能の完全なコレクションの明確な描写を提供することです。
Railsサービスのサードパーティプロバイダーは通常、APIをラップするgemを介して、サービスをアプリケーションに非常に簡単に統合できます。しかし、外部サービスが停止したり、実行が非常に遅くなったりした場合はどうなりますか?
過去10年間の音楽業界の統計
これらの呼び出しのブロックを回避するには、要求の通常の処理中にRailsアプリケーションでこれらのサービスを直接呼び出すのではなく、可能な場合は、何らかのバックグラウンドジョブキューイングサービスに移動する必要があります。この目的でRailsアプリケーションで使用される人気のあるgemには、次のものがあります。
処理をバックグラウンドジョブキューに委任することが非現実的または実行不可能な場合は、外部サービスがダウンしたり問題が発生したりする避けられない状況に対して、アプリケーションに十分なエラー処理とフェイルオーバーのプロビジョニングがあることを確認する必要があります。 。また、外部サービスを使用せずにアプリケーションをテストして(おそらく、アプリケーションが存在するサーバーをネットワークから削除することによって)、予期しない結果が発生しないことを確認する必要があります。
Rails ’ データベース移行メカニズム データベースのテーブルと行を自動的に追加および削除するための命令を作成できます。これらの移行を含むファイルには順番に名前が付けられているため、最初から再生して、空のデータベースを本番環境と同じスキーマに移動できます。したがって、これは、アプリケーションのデータベーススキーマに対するきめ細かい変更を管理し、Railsの問題を回避するための優れた方法です。
これはプロジェクトの開始時には確かにうまく機能しますが、時間が経つにつれて、データベースの作成プロセスにかなりの時間がかかることがあり、移行が間違って配置されたり、順序が狂ったり、同じデータベースサーバーを使用する他のRailsアプリケーションから導入されたりすることがあります。
Railsは、現在のスキーマの表現をdb/schema.rb
というファイルに作成します。 (デフォルト)これは通常、データベースの移行が実行されるときに更新されます。 schema.rb
rake db:schema:dump
を実行することにより、移行が存在しない場合でもファイルを生成できます。仕事。 Railsでよくある間違いは、ソースリポジトリへの新しい移行をチェックすることですが、対応して更新されるschema.rb
はチェックしません。ファイル。
移行が手に負えなくなって実行に時間がかかりすぎたり、データベースが適切に作成されなくなったりした場合、開発者は古い移行ディレクトリをクリアし、新しいスキーマをダンプして、そこから続行することを恐れないでください。新しい開発環境をセットアップするには、rake db:schema:load
が必要になります。 rake db:migrate
ではなくほとんどの開発者が依存しています。
これらの幾つか 問題が議論されます Railsガイドにもあります。
Railsフレームワークを使用すると、さまざまな種類の攻撃に影響されない安全なアプリケーションを簡単に作成できます。これのいくつかは、ブラウザとのセッションを保護するために秘密のトークンを使用することによって達成されます。このトークンは現在config/secrets.yml
に格納されており、そのファイルは本番サーバーの環境変数からトークンを読み取りますが、過去のバージョンのRailsではトークンがconfig/initializers/secret_token.rb
に含まれていました。このファイルは、アプリケーションの他の部分と一緒にソースコードリポジトリに誤ってチェックインされることがよくあります。これが発生すると、 リポジトリにアクセスできる人は誰でも、アプリケーションのすべてのユーザーを簡単に侵害できるようになりました 。
したがって、リポジトリ構成ファイルを確認する必要があります(例:.gitignore
行く ユーザー)は、トークンを含むファイルを除外します。その後、本番サーバーは、環境変数または次のようなメカニズムからトークンを取得できます。 dotenv gem 提供します。
Railsは、ビルドに必要な醜い詳細の多くを隠す強力なフレームワークです。 堅牢なWebアプリケーション 。これによりRailsWebアプリケーションの開発がはるかに高速になりますが、開発者は潜在的な設計およびコーディングエラーに注意を払い、アプリケーションが成長しても簡単に拡張および保守できるようにする必要があります。
開発者は、アプリケーションの速度が低下し、信頼性が低下し、安全性が低下する可能性のある問題にも注意する必要があります。フレームワークを研究し、開発プロセス全体で行っているアーキテクチャ、設計、コーディングのトレードオフを完全に理解して、高品質で高性能なアプリケーションを確保することが重要です。
関連: Ruby on Railsの利点は何ですか? 20年のプログラミングの後、私はRailsを使用します