Cara Menggunakan Rails Helpers: Demonstrasi Carousel Bootstrap
Diterbitkan: 2022-03-11Salah satu yang paling disalahgunakan, disalahpahami, dan diabaikan dari semua struktur built-in Rails adalah view helper . Terletak di direktori app/helpers
Anda dan dihasilkan secara default dengan setiap proyek Rails baru, helper sering kali mendapatkan reputasi buruk sebagai tempat pembuangan untuk metode satu kali yang digunakan di seluruh lapisan tampilan aplikasi. Sayangnya, Rails sendiri mendorong kurangnya struktur dan organisasi yang buruk ini dengan memasukkan semua helper ke dalam setiap tampilan secara default, menciptakan namespace global yang tercemar.
Tetapi bagaimana jika pembantu Anda bisa lebih semantik, lebih terorganisir, dan bahkan dapat digunakan kembali di seluruh proyek? Bagaimana jika itu bisa lebih dari sekadar fungsi satu kali yang ditaburkan di seluruh tampilan, tetapi metode canggih yang menghasilkan markup kompleks dengan mudah sehingga membuat tampilan Anda bebas dari logika dan kode bersyarat?
Mari kita lihat bagaimana melakukan ini saat membangun carousel gambar, dengan kerangka kerja Bootstrap Twitter yang sudah dikenal dan beberapa pemrograman berorientasi objek kuno yang bagus.
Kapan harus menggunakan pembantu Rails
Ada banyak pola desain berbeda yang dapat digunakan dalam layer tampilan Rails: presenter, dekorator, sebagian, serta pembantu, hanya untuk beberapa nama. Aturan praktis saya yang sederhana adalah bahwa helper bekerja dengan baik ketika Anda ingin menghasilkan markup HTML yang memerlukan struktur tertentu, kelas CSS tertentu, logika kondisional, atau penggunaan kembali di halaman yang berbeda.
Contoh terbaik dari kekuatan pembantu Rails ditunjukkan oleh FormBuilder
dengan semua metode terkait untuk menghasilkan bidang input, pilih tag, label, dan struktur HTML lainnya. Metode bermanfaat ini menghasilkan markup untuk Anda dengan semua atribut yang relevan disetel dengan benar. Kenyamanan seperti inilah yang membuat kami semua jatuh cinta pada Rails sejak awal.
Manfaat menggunakan helper yang dibuat dengan baik sama dengan kode yang ditulis dengan baik dan bersih: enkapsulasi, pengurangan pengulangan kode (DRY), dan menjauhkan logika dari pandangan.
Anatomi Korsel Bootstrap Twitter
Twitter Bootstrap adalah kerangka kerja front-end yang banyak digunakan yang dilengkapi dengan dukungan bawaan untuk komponen umum seperti modals, tab, dan carousel gambar. Komponen Bootstrap ini adalah kasus penggunaan yang bagus untuk pembantu kustom karena markup sangat terstruktur, memerlukan kelas, ID, dan atribut data tertentu untuk disetel dengan benar agar JavaScript berfungsi, dan menyetel atribut tersebut memerlukan sedikit logika kondisional.
Korsel Bootstrap 3 memiliki markup berikut:
<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>
Seperti yang Anda lihat, ada tiga struktur utama: (1) indikator (2) slide gambar (3) kontrol slide.
Tujuannya adalah untuk dapat membangun metode pembantu tunggal yang mengambil kumpulan gambar dan merender seluruh komponen carousel ini, memastikan bahwa data, id
, atribut href
, dan kelas CSS semuanya diatur dengan benar.
Pembantu
Mari kita mulai dengan garis besar dasar helper:
# 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
Metode pembantu carousel_for
akan mengembalikan markup carousel lengkap untuk URL gambar yang diberikan. Daripada membangun serangkaian metode individual untuk merender setiap bagian dari carousel (yang akan mengharuskan kita menyebarkan koleksi gambar dan informasi stateful lainnya ke setiap metode), kita akan membuat kelas Ruby lama biasa yang disebut Carousel
untuk mewakili data carousel. Kelas ini akan mengekspos metode html
yang mengembalikan markup yang dirender sepenuhnya. Kami menginisialisasinya dengan kumpulan gambar URL images
, dan tampilan konteks view
.
Perhatikan bahwa parameter view
adalah turunan dari ActionView
, di mana semua helper Rails digabungkan. Kami meneruskannya ke instance objek kami untuk mendapatkan akses ke metode pembantu bawaan Rails seperti link_to
, content_tag
, image_tag
, dan safe_join
, yang akan kami gunakan untuk membangun markup di dalam kelas. Kami juga akan menambahkan makro delegate
, sehingga kami dapat memanggil metode tersebut secara langsung, tanpa merujuk ke 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
Kita tahu bahwa korsel terdiri dari tiga komponen terpisah, jadi mari kita hentikan metode yang pada akhirnya akan memberi kita markup untuk masing-masing komponen, lalu minta metode html
untuk menggabungkannya ke dalam tag div
kontainer, menerapkan kelas Bootstrap yang diperlukan untuk korsel itu sendiri.

safe_join
adalah metode bawaan yang berguna yang menggabungkan kumpulan string dan memanggil html_safe
pada hasilnya. Ingat, kami memiliki akses ke metode tersebut melalui parameter view
, yang kami berikan saat membuat instance.
Kami akan membangun indikatornya terlebih dahulu:
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
Indikatornya adalah daftar ol
sederhana yang memiliki elemen daftar item li
untuk setiap gambar dalam koleksi. Indikator gambar yang sedang aktif membutuhkan kelas CSS yang active
, jadi kami akan memastikan bahwa itu disetel untuk indikator pertama yang kami buat. Ini adalah contoh logika yang bagus yang biasanya harus dalam tampilan itu sendiri.
Perhatikan bahwa indikator perlu merujuk id
unik dari elemen carousel yang memuat (jika ada lebih dari satu carousel pada halaman). Kami dapat dengan mudah menghasilkan id
ini di penginisialisasi dan menggunakannya di seluruh kelas lainnya (khususnya di dalam indikator dan kontrol). Melakukan ini secara terprogram di dalam metode helper memastikan bahwa id
akan konsisten di seluruh elemen carousel. Ada banyak waktu ketika kesalahan ketik kecil atau mengubah id
di satu tempat tetapi tidak di tempat lain akan menyebabkan korsel rusak; itu tidak akan terjadi di sini karena semua elemen secara otomatis mereferensikan id
yang sama.
def initialize(view, images) # ... @uid = SecureRandom.hex(6) end attr_accessor :uid
Selanjutnya adalah slide gambar:
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
Kami hanya mengulangi setiap gambar yang kami berikan ke instance Carousel
dan membuat markup yang tepat: tag gambar yang dibungkus dengan div
dengan item
kelas CSS, sekali lagi memastikan untuk menambahkan kelas active
ke yang pertama kami buat.
Terakhir, kita membutuhkan kontrol Sebelumnya/Berikutnya:
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
Kami membuat tautan yang mengontrol gerakan korsel bolak-balik di antara gambar. Perhatikan penggunaan uid
lagi; tidak perlu khawatir tidak menggunakan ID yang tepat di semua tempat yang berbeda dalam struktur carousel, secara otomatis konsisten dan unik.
Produk jadi:
Dengan itu, pembantu carousel kami selesai. Ini dia secara keseluruhan:
# 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
Penolong beraksi:
Akhirnya, untuk menjelaskan intinya, mari kita lihat contoh singkat bagaimana penolong ini dapat membuat hidup kita lebih mudah. Katakanlah kami sedang membangun situs web untuk daftar sewa apartemen. Setiap objek Apartment
memiliki daftar URL gambar:
class Apartment def image_urls # ... end end
Dengan carousel helper kami, kami dapat membuat seluruh carousel Bootstrap dengan satu panggilan ke carousel_for
, sepenuhnya menghapus logika yang cukup kompleks dari tampilan:
<% apartment = Apartment.new %> # ... <%= carousel_for(apartment.image_urls) %>
Tidak yakin kapan harus menggunakan pembantu tampilan Rails? Berikut demonstrasi.
Menciak
Kesimpulan
Dengan menggunakan teknik sederhana namun kuat ini, kami telah memindahkan sejumlah besar markup dan logika keluar dari lapisan tampilan dan menjadi fungsi pembantu yang dapat digunakan untuk merender komponen korsel di mana saja hanya dengan panggilan carousel_for(some_images)
. Helper generik ini dapat digunakan di semua proyek Rails Anda kapan pun Anda menggunakan Twitter Bootstrap. Yang terpenting, Anda sekarang memiliki alat baru di toolkit Anda yang juga dapat Anda gunakan untuk komponen khusus proyek.
Jadi, lain kali Anda menemukan diri Anda mengetik dan mengetik ulang jenis markup yang sama dan menyematkan logika kondisional ke dalam tampilan Anda, lihat apakah fungsi pembantu hanya menunggu untuk ditulis untuk membuat hidup Anda lebih mudah.