Railsヘルパーの使用方法:ブートストラップカルーセルのデモンストレーション

公開: 2022-03-11

Railsのすべての組み込み構造の中で最も誤用され、誤解され、無視されているものの1つは、ビューヘルパーです。 app/helpersディレクトリにあり、すべての新しいRailsプロジェクトでデフォルトで生成されるヘルパーは、アプリケーションのビューレイヤー全体で使用される1回限りのメソッドのダンプグラウンドであるという評判が悪いことがよくあります。 残念ながら、Rails自体は、デフォルトですべてのヘルパーをすべてのビューに含め、汚染されたグローバル名前空間を作成することにより、この構造の欠如と貧弱な組織を助長しています。

しかし、ヘルパーがよりセマンティックで、より適切に編成され、プロジェクト間で再利用できるとしたらどうでしょうか。 ビュー全体に散在する1回限りの関数ではなく、複雑なマークアップを簡単に生成する強力なメソッドで、ビューに条件付きロジックやコードがない場合はどうでしょうか。

おなじみのTwitterBootstrapフレームワークと古き良きオブジェクト指向プログラミングを使用して、画像カルーセルを構築するときにこれを行う方法を見てみましょう。

Railsヘルパーを使用する場合

Railsのビューレイヤーで使用できるさまざまなデザインパターンがあります。たとえば、プレゼンター、デコレーター、パーシャル、ヘルパーなどです。 私の簡単な経験則では、特定の構造、特定のCSSクラス、条件付きロジック、または異なるページ間での再利用を必要とするHTMLマークアップを生成する場合、ヘルパーはうまく機能します。

Railsヘルパーの力の最良の例は、入力フィールド、選択タグ、ラベル、およびその他のHTML構造を生成するためのすべての関連メソッドを備えたFormBuilderによって示されます。 これらの便利なメソッドは、関連するすべての属性が適切に設定されたマークアップを生成します。 このような便利さが、私たち全員がそもそもRailsに恋をした理由です。

巧妙に作成されたヘルパーを使用する利点は、よく書かれたクリーンなコードと同じです。つまり、カプセル化、コードの繰り返し(DRY)の削減、ロジックが見えないようにすることです。

Twitterブートストラップカルーセルの構造

Twitter Bootstrapは、広く使用されているフロントエンドフレームワークであり、モーダル、タブ、画像カルーセルなどの一般的なコンポーネントのサポートが組み込まれています。 これらのブートストラップコンポーネントは、マークアップが高度に構造化されており、JavaScriptが機能するために特定のクラス、ID、およびデータ属性を正しく設定する必要があり、これらの属性を設定するには少し条件付きロジックが必要なため、カスタムヘルパーの優れたユースケースです。

Bootstrap3カルーセルには次のマークアップがあります。

 <div class="carousel slide" data-ride="carousel"> <!-- Indicators --> <ol class="carousel-indicators"> <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> <li data-target="#carousel-example-generic" data-slide-to="1"></li> <li data-target="#carousel-example-generic" data-slide-to="2"></li> </ol> <!-- Wrapper for slides --> <div class="carousel-inner"> <div class="item active"> <img src="..." alt="..."> </div> <div class="item"> <img src="..." alt="..."> </div> ... </div> <!-- Controls --> <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"> <span class="glyphicon glyphicon-chevron-left"></span> </a> <a class="right carousel-control" href="#carousel-example-generic" data-slide="next"> <span class="glyphicon glyphicon-chevron-right"></span> </a> </div>

ご覧のとおり、3つの主要な構造があります。(1)インジケーター(2)画像スライド(3)スライドコントロール。

中央にワイドスクリーン比の長方形(スライド)があり、下部に3つの小さな円(インジケーター)がある青写真。左右の矢印がそれぞれ付いた2つの細い長方形(コントロール)が側面にあります。
ブートストラップカルーセルのパーツ。

目標は、画像のコレクションを取得してこのカルーセルコンポーネント全体をレンダリングする単一のヘルパーメソッドを構築し、データ、 idhref属性、およびCSSクラスがすべて適切に設定されるようにすることです。

ヘルパー

ヘルパーの基本的な概要から始めましょう:

 # app/helpers/carousel_helper.rb module CarouselHelper def carousel_for(images) Carousel.new(self, images).html end class Carousel def initialize(view, images) @view, @images = view, images end def html # TO FILL IN end private attr_accessor :view, :images end end

ヘルパーメソッドcarousel_forは、指定された画像URLの完全なカルーセルマークアップを返します。 カルーセルの各部分をレンダリングするための一連の個別のメソッドを構築するのではなく(画像コレクションやその他のステートフル情報を各メソッドに渡す必要があります)、 Carouselと呼ばれる新しいプレーンオールドルビークラスを作成します。カルーセルデータを表します。 このクラスは、完全にレンダリングされたマークアップを返すhtmlメソッドを公開します。 画像URL imagesのコレクションとビューコンテキストviewで初期化します。

viewパラメーターはActionViewのインスタンスであり、すべてのRailsヘルパーが混在していることに注意してください。 これをオブジェクトインスタンスに渡して、 link_tocontent_tagimage_tagsafe_joinなどのRailsの組み込みヘルパーメソッドにアクセスします。これらのメソッドを使用して、クラス内でマークアップを構築します。 また、 delegateマクロを追加して、 viewを参照せずにこれらのメソッドを直接呼び出すことができるようにします。

 def html content = view.safe_join([indicators, slides, controls]) view.content_tag(:div, content, class: 'carousel slide') end private attr_accessor :view, :images delegate :link_to, :content_tag, :image_tag, :safe_join, to: :view def indicators # TO FILL IN end def slides # TO FILL IN end def controls # TO FILL IN end

カルーセルは3つの別個のコンポーネントで構成されていることがわかっているので、最終的にそれぞれのマークアップを提供するメソッドをスタブアウトしてから、 htmlメソッドでそれらをコンテナdivタグに結合し、カルーセル自体に必要なBootstrapクラスを適用します。

safe_joinは、文字列のコレクションを連結し、結果html_safeを呼び出す便利な組み込みメソッドです。 インスタンスの作成時に渡したviewパラメータを介してこれらのメソッドにアクセスできることを忘れないでください。

最初に指標を作成します。

 def indicators items = images.count.times.map { |index| indicator_tag(index) } content_tag(:ol, safe_join(items), class: 'carousel-indicators') end def indicator_tag(index) options = { class: (index.zero? ? 'active' : ''), data: { target: uid, slide_to: index } } content_tag(:li, '', options) end

インジケーターは、コレクション内の各画像のリストアイテムli要素を持つ単純な順序付きリストolです。 現在アクティブな画像インジケーターにはactive CSSクラスが必要なので、作成する最初のインジケーターに設定されていることを確認します。 これは、通常はビュー自体に含まれている必要があるロジックの優れた例です。

インジケーターは、含まれているカルーセル要素の一意のidを参照する必要があることに注意してください(ページに複数のカルーセルがある場合)。 このidは初期化子で簡単に生成でき、クラスの残りの部分全体(特にインジケーターとコントロール内)で使用できます。 ヘルパーメソッド内でこれをプログラムで実行すると、 idがカルーセル要素間で一貫していることが保証されます。 小さなタイプミスやidを1つの場所で変更しても、他の場所では変更しないと、カルーセルが破損することがよくあります。 すべての要素が自動的に同じidを参照するため、ここでは発生しません。

 def initialize(view, images) # ... @uid = SecureRandom.hex(6) end attr_accessor :uid

次は画像スライドです。

 def slides items = images.map.with_index { |image, index| slide_tag(image, index.zero?) } content_tag(:div, safe_join(items), class: 'carousel-inner') end def slide_tag(image, is_active) options = { class: (is_active ? 'item active' : 'item'), } content_tag(:div, image_tag(image), options) end

Carouselインスタンスに渡した各画像を繰り返し処理し、適切なマークアップを作成します。 item CSSクラスでdivにラップされた画像タグを作成し、最初に作成したクラスにactiveクラスを追加します。

最後に、Previous/Nextコントロールが必要です。

 def controls safe_join([control_tag('left'), control_tag('right')]) end def control_tag(direction) options = { class: "#{direction} carousel-control", data: { slide: direction == 'left' ? 'prev' : 'next' } } icon = content_tag(:i, nil, class: "glyphicon glyphicon-chevron-#{direction}") control = link_to(icon, "##{uid}", options) end

画像間のカルーセルの前後の動きを制御するリンクを作成します。 uidの使用法に再度注意してください。 カルーセル構造内のすべての異なる場所で正しいIDを使用しないことを心配する必要はありません。これは、自動的に一貫性があり、一意です。

完成品:

これで、カルーセルヘルパーが完成しました。 ここにその全体があります:

 # app/helpers/carousel_helper.rb module CarouselHelper def carousel_for(images) Carousel.new(self, images).html end class Carousel def initialize(view, images) @view, @images = view, images @uid = SecureRandom.hex(6) end def html content = safe_join([indicators, slides, controls]) content_tag(:div, content, id: uid, class: 'carousel slide') end private attr_accessor :view, :images, :uid delegate :link_to, :content_tag, :image_tag, :safe_join, to: :view def indicators items = images.count.times.map { |index| indicator_tag(index) } content_tag(:ol, safe_join(items), class: 'carousel-indicators') end def indicator_tag(index) options = { class: (index.zero? ? 'active' : ''), data: { target: uid, slide_to: index } } content_tag(:li, '', options) end def slides items = images.map.with_index { |image, index| slide_tag(image, index.zero?) } content_tag(:div, safe_join(items), class: 'carousel-inner') end def slide_tag(image, is_active) options = { class: (is_active ? 'item active' : 'item'), } content_tag(:div, image_tag(image), options) end def controls safe_join([control_tag('left'), control_tag('right')]) end def control_tag(direction) options = { class: "#{direction} carousel-control", data: { slide: direction == 'left' ? 'prev' : 'next' } } icon = content_tag(:i, '', class: "glyphicon glyphicon-chevron-#{direction}") control = link_to(icon, "##{uid}", options) end end end

動作中のヘルパー:

最後に、要点を理解するために、このヘルパーがどのように私たちの生活を楽にすることができるかについての簡単な例を見てみましょう。 アパートの賃貸物件のウェブサイトを構築しているとしましょう。 各Apartmentオブジェクトには、画像URLのリストがあります。

 class Apartment def image_urls # ... end end

カルーセルヘルパーを使用すると、 carousel_forを1回呼び出すだけで、ブートストラップカルーセル全体をレンダリングでき、ビューからかなり複雑なロジックを完全に削除できます。

 <% apartment = Apartment.new %> # ... <%= carousel_for(apartment.image_urls) %> 

Railsビューヘルパーをいつ使用するかわからない場合は、 これがデモンストレーションです。

つぶやき

結論

このシンプルでありながら強力な手法を使用して、大量のマークアップとロジックをビューレイヤーから、 carousel_for(some_images)呼び出しだけでどこにでもカルーセルコンポーネントをレンダリングするために使用できるヘルパー関数に移動しました。 。 この汎用ヘルパーは、Twitter Bootstrapを使用しているときはいつでも、すべてのRailsプロジェクトで使用できます。 最も重要なことは、プロジェクト固有のコンポーネントにも使用できる新しいツールがツールキットに含まれていることです。

したがって、次に同じ種類のマークアップを入力して再入力し、条件付きロジックをビューに埋め込む場合は、作業を楽にするためにヘルパー関数が作成されるのを待っているかどうかを確認してください。