Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyonRailsのビューパターンとアンチパターン

RubyonRailsパターンとアンチパターンシリーズの第3回へようこそ。以前の投稿では、Railsモデルに関連するだけでなく、一般的なパターンとアンチパターンについても説明しました。この投稿では、weareがRailsビューに関連するいくつかのパターンとアンチパターンについて説明します。

Railsビューは完全に機能し、高速である場合もあれば、あらゆる種類の問題が発生する場合もあります。ビューの処理方法に対する信頼を高めたい場合、またはトピックについて詳しく知りたい場合は、このブログ投稿をご覧ください。あなた。さっそく飛び込みましょう。

ご存知かもしれませんが、Railsフレームワークは設定より規約に従います。また、RailsはModel-View-Controller(MVC)パターンで大きいため、モットーは当然、ビューコードにも適用されます。これには、マークアップ(ERBまたはSlimファイル)、JavaScriptおよびCSSファイルが含まれます。一見すると、Viewレイヤーは非常に単純で簡単だと思われるかもしれませんが、最近では、Viewレイヤーにはさまざまなテクノロジーが混在していることに注意してください。

ビューではJavaScript、HTML、およびCSSを使用します。これらの3つは、コードの混乱と混乱につながる可能性があります—長期的にはあまり意味のない実装につながります。幸いなことに、今日はRailsViewレイヤーに関するいくつかの一般的な問題と解決策を紹介します。

パワーリフティングビュー

これはそれほど頻繁には起こらない間違いですが、そうなると、それは目障りです。時々、人々はドメインロジックやクエリをビューの中に直接置く傾向があります。これにより、ビューレイヤーが重労働またはパワーリフティングを実行します。興味深いのは、Railsが実際にこれを簡単に実行できることです。これに関しては、「セーフティネット」はなく、ビューレイヤーでやりたいことが何でもできます。

定義上、MVCパターンのビューレイヤーにはpresentationlogicが含まれている必要があります。ドメインロジックやデータのクエリに煩わされることはありません。 Railsでは、ERBファイル(Embedded Ruby)を取得して、HTMLに評価されるRubyコードを記述できるようにします。インデックスページに曲を一覧表示するウェブサイトの例を考えると、ビューロジックはapp/views/songs/index.html.erbにあります。 。

「パワーリフティング」の意味とそうでないことを説明するために、次の例を見てみましょう。

# app/views/songs/index.html.erb
 
<div class="songs">
  <% Song.where(published: true).order(:title) do |song| %>
    <section id="song_<%= song.id %>">
      <span><%= song.title %></span>
 
      <span><%= song.description %></span>
 
      <a href="<%= song.download_url %>">Download</a>
    </section>
  <% end %>
</div>

ここでの大きなアンチパターンは、マークアップ内の曲のフェッチです。データをフェッチする責任は、コントローラーまたはコントローラーから呼び出されているサービスに委任する必要があります。私は時々、人々がコントローラーでいくつかのデータを準備し、後でビューでより多くのデータをフェッチするのを目にします。これは悪い設計であり、クエリでデータベースにストレスをかけることが多いため、Webサイトの速度が低下します。

代わりに、@songsを公開する必要があります コントローラアクションからのインスタンス変数をマークアップで呼び出します。次のようになります。

class SongsController < ApplicationController
  ...
 
  def index
    @songs = Song.all.where(published: true).order(:title)
  end
 
  ...
end
# app/views/songs/index.html.erb
 
<div class="songs">
  <% @songs.each do |song| %>
    <section id="song_<%= song.id %>">
      <span><%= song.title %></span>
 
      <span><%= song.description %></span>
 
      <a href="<%= song.download_url %>">Download</a>
    </section>
  <% end %>
</div>

これらの例は完璧にはほど遠いです。コントローラコードを読みやすくし、SQLパスタを避けたい場合は、前のブログ投稿を確認することをお勧めします。また、ビューレイヤーのロジックを省略すると、他の人がそれからソリューションを構築しようとする可能性が高くなります。

レールが提供するものを活用する

ここでは短くしておきます。フレームワークとしてのRubyonRailsには、特にビュー内に多くのニートヘルパーが付属しています。これらの気の利いた小さなヘルパーを使用すると、Viewレイヤーをすばやく簡単に構築できます。 Railsの初心者ユーザーは、次のようにERbファイル内に完全なHTMLを記述したくなるかもしれません。

# app/views/songs/new.html.erb
 
<form action="/songs" method="post">
  <div class="field">
    <label for="song_title">Title</label>
    <input type="text" name="song[title]" id="song_title">
  </div>
 
  <div class="field">
    <label for="song_description">Description</label>
    <textarea name="song[description]" id="song_description"></textarea>
  </div>
 
  <div class="field">
    <label for="song_download_url">Download URL</label>
    <textarea name="song[download_url]" id="song_download_url"></textarea>
  </div>
 
  <input type="submit" name="commit" value="Create Song">
</form>

このHTMLを使用すると、下のスクリーンショットに示すように、新しい曲の素敵なフォームが得られるはずです。

しかし、Railsを使用する場合は、Railsがすぐそこに戻ってくるので、そのようなプレーンHTMLを作成する必要はありません。 form_withを使用できます HTMLを生成するヘルパーを表示します。 form_with Rails 5.1で導入され、form_tagを置き換えるためにそこにあります およびform_for それは誰かに馴染みがあるかもしれません。 form_withがどのようになっているのか見てみましょう 余分なコードを書くことから私たちを解放することができます:

<%= form_with(model: song, local: true) do |form| %>
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>
 
  <div class="field">
    <%= form.label :description %>
    <%= form.text_area :description %>
  </div>
 
  <div class="field">
    <%= form.label :download_url do %>
      Download URL
    <% end %>
    <%= form.text_area :download_url %>
  </div>
 
  <%= form.submit %>
<% end %>

HTMLを生成するだけでなく、form_with また、CSRF攻撃を防ぐ認証トークンを生成します。したがって、ほとんどの場合、Railsフレームワークでうまく機能する可能性があるため、指定されたヘルパーを使用しない方がよいでしょう。プレーンなHTMLフォームを送信しようとすると、リクエストとともに送信された無効な認証トークンがあったため、失敗します。

form_withの他に 、labeltext_area 、およびsubmit ヘルパー、Railsですぐに使用できるこれらのビューヘルパーがたくさんあります。それらはあなたの生活を楽にするためにあり、あなたはそれらをよりよく知るようになるべきです。 「オールスター」の1つは、間違いなくlink_toです。 :

<%= link_to "Songs", songs_path %>

次のHTMLが生成されます:

<a href="/songs">Songs</a>

この投稿はツールオンであり、それらすべてを通過することは今日のトピックの一部ではないため、各ヘルパーについてはあまり詳しく説明しません。 gothroughRailsアクションビューヘルパーガイドを使用して、Webサイトに必要なものを選択することをお勧めします。

ビューコードの再利用と整理

完璧なWebアプリケーションを想像してみましょう。完璧なユースケースでは、if-elseステートメントはなく、コントローラーからデータを取得してHTMLタグの間に配置する純粋なコードだけです。この種のアプリケーションは、おそらくハッカソンや夢の中に存在しますが、実際のアプリケーションには、ビューをレンダリングするときに多数のブランチと条件があります。

ページの一部を表示するためのロジックが複雑になりすぎた場合はどうすればよいですか?そこからどこへ行くの?一般的な答えは、おそらく最新のJavaScriptライブラリまたはフレームワークに手を伸ばし、複雑なものを構築することです。ただし、この投稿はRailsビューに関するものなので、Railsビュー内にあるオプションを見てみましょう。

アフターマーケット(カスタム)ヘルパー

曲の下に召喚状(CTA)ボタンを表示するとします。ただし、落とし穴があります。曲にはダウンロードURLが含まれているか、何らかの理由で曲が欠落している可能性があります。次のようなものをコーディングしたくなるかもしれません:

app/views/songs/show.html.erb
 
...
 
<div class="song-cta">
  <% if @song.download_url %>
    <%= link_to "Download", download_url %>
  <% else %>
    <%= link_to "Subscribe to artists updates",
                artist_updates_path(@song.artist) %>
  <% end %>
</div>
 
...

上記の例を分離されたプレゼンテーションロジックとして見ると、それほど悪くはありませんよね?ただし、これらの条件付きレンダリングがさらにあると、コードが読みにくくなります。また、特に条件が多い場合に、どこかで適切にレンダリングされない可能性が高くなります。

これらと戦う1つの方法は、別のヘルパーにそれらを抽出することです。幸い、Railsはカスタムヘルパーを簡単に作成する方法を提供してくれます。 app/helpersSongsHelperを作成できます 、そのように:

module SongsHelper
  def song_cta_link
    content_tag(:div, class: 'song-cta') do
      if @song.download_url
        link_to "Download", @song.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(@song.artist)
      end
    end
  end
end

曲のショーページを開いても同じ結果が得られますが、この例を少し良くすることができます。上記の例では、インスタンス変数@songを使用しました 。 @songの場所でこのヘルパーを使用することにした場合、これは利用できない可能性があります nilです 。したがって、インスタンス変数の形式で外部依存関係を切り離すには、次のようにヘルパーに引数を渡すことができます。

module SongsHelper
  def song_cta_link(song)
    content_tag(:div, class: 'song-cta') do
      if song.download_url
        link_to "Download", song.download_url
      else
        link_to "Subscribe to artists updates",
                artist_updates_path(song.artist)
      end
    end
  end
end

次に、ビューで、次のようにヘルパーを呼び出すことができます:

app/views/songs/show.html.erb
 
...
 
<%= song_cta_link(@song) %>
 
...

これで、以前と同じ結果がビューに表示されるはずです。ヘルパーを使用することの良い点は、ヘルパーのテストを作成して、将来的にヘルパーが回帰しないことを確認できることです。短所は、それらがグローバルに定義されていることであり、ヘルパー名がアプリ全体で一意であることを確認する必要があります。

Railsカスタムヘルパーの作成があまり好きでない場合は、いつでもtheDraper gemを使用してビューモデルパターンをオプトインできます。または、ここで独自のビューモデルパターンをロールすることもできますが、それほど複雑ではありません。 Webアプリを使い始めたばかりの場合は、カスタムヘルパーを作成してゆっくりと開始することをお勧めします。それで問題が発生する場合は、他のソリューションを使用してください。

ビューを乾かす

Railsを使い始めたときに本当に気に入ったのは、信じられないほどのマークアップを簡単に乾かすことができることでした。 Railsを使用すると、パーシャルを作成できます。これは、どこにでも含めることができる再利用可能なコードピースです。たとえば、複数の場所で曲をレンダリングしていて、複数のファイルに同じコードがある場合は、曲を部分的に作成するのが理にかなっています。

以下に示すように曲を表示するとします:

# app/views/songs/show.html.erb
 
<p id="notice"><%= notice %></p>
 
<p>
  <strong>Title:</strong>
  <%= @song.title %>
</p>
 
<p>
  <strong>Description:</strong>
  <%= @song.description %>
</p>
 
<%= song_cta_link %>
 
<%= link_to 'Edit', edit_song_path(@song) %> |
<%= link_to 'Back', songs_path %>

ただし、同じマークアップの別のページにも表示する必要があります。次に、app/views/songs/_song.html.erbのようなアンダースコアプレフィックスを使用して新しいファイルを作成できます。 。

# app/views/songs/_song.html.erb
 
<p>
  <strong>Title:</strong>
  <%= @song.title %>
</p>
 
<p>
  <strong>Description:</strong>
  <%= @song.description %>
</p>
 
<%= song_cta_link(@song) %>

そして、曲の一部を含めたい場合は、次のようにします。

...
 
<%= render "song" %>
 
...

Railsは、_songかどうかの自動ルックアップを実行します 部分的に存在し、それをレンダリングします。カスタムヘルパーを使用した例と同様に、インスタンス変数@songを削除するのが最適です。 私たちの部分で。

 
# app/views/songs/_song.html.erb
<p>
  <strong>Title:</strong>
  <%= song.title %>
</p>
 
<p>
  <strong>Description:</strong>
  <%= song.description %>
</p>
 
<%= song_cta_link(song) %>

次に、曲の変数をパーシャルに渡して、再利用しやすくし、他の場所に含めるのに適したものにする必要があります。

...
 
<%= render "song", song: @song %>
 
...

最終的な考え

この投稿のすべての人です。要約すると、RailsViewレルムで遭遇する可能性のあるいくつかのパターンとアンチパターンについて説明しました。ここにいくつかのポイントがあります:

  • UIの複雑なロジックは避けてください(ビューに多くのパワーリフティングを行わせないでください)
  • ビューヘルパーの観点から、Railsがすぐに使えるものを学びましょう。
  • カスタムヘルパーとパーシャルを使用してコードを構造化して再利用します
  • インスタンス変数に過度に依存しないでください。

次の投稿では、RailsControllerのパターンとアンチパターンについて説明します。しばらくお待ちください。

次の人まで、乾杯!

P.S。 Ruby Magicの投稿をマスコミから離れたらすぐに読みたい場合は、Ruby Magicニュースレターを購読して、投稿を1つも見逃さないでください。


  1. RubyonRailsでスコープを使用する方法

    Railsのスコープとは何ですか?なぜそれが役立つのですか? まあ… スコープは、scopeを使用してRailsモデル内で定義するカスタムクエリです。 メソッド。 すべてのスコープには2つの引数があります : コードでこのスコープを呼び出すために使用する名前。 クエリを実装するラムダ。 このように見えます : class Fruit < ApplicationRecord scope :with_juice, -> { where(juice > 0) } end スコープを呼び出した結果、ActiveRecord::Relationを取得します オブジ

  2. Ruby on Railsとは何ですか?なぜそれが役立つのですか?

    Ruby on Rails(RoRの場合もある)は、最も人気のあるオープンソースのWebアプリケーションフレームワークです。 Rubyプログラミング言語で構築されています。 Railsを使用すると、単純なものから複雑なものまで、アプリケーションの構築に役立ちます。Railsで実行できることには制限がありません。 フレームワークとは何ですか? フレームワークは、ソフトウェアを作成するときに使用する特定の構造を提供するコード、ツール、およびユーティリティのコレクションです。 この構造により、コードがより整理されます。 正しく使うことを学ぶと、作業が簡単になります。 レールは正確に何を