Computer >> Máy Tính >  >> Lập trình >> Ruby

Giới thiệu về ViewComponent Gem

Lấy cảm hứng từ React, ViewComponents là các đối tượng Ruby được sử dụng để xây dựng đánh dấu cho các khung nhìn hiển thị. ViewComponent là một khuôn khổ để xây dựng các thành phần xem có thể sử dụng lại, có thể kiểm tra và đóng gói trong Rails. Thông thường, các khung nhìn có thể tái sử dụng được tạo trong Rails bằng cách sử dụng các thành phần và sau đó được hiển thị trong các khung nhìn khác nhau theo yêu cầu, nhưng với sự ra đời của viên ngọc ViewComponent, các thành phần có thể được hoán đổi cho các thành phần khung nhìn, vì chúng mang lại nhiều lợi thế hơn. Hãy đi sâu vào những lợi thế này là gì.

Khi nào và Tại sao tôi nên sử dụng ViewComponents?

Như đã nêu trước đó, các thành phần chế độ xem có thể sử dụng lại và có thể kiểm tra được. Do đó, chúng có thể được áp dụng bất cứ khi nào một chế độ xem được sử dụng lại hoặc được hưởng lợi từ việc được kiểm tra trực tiếp. Một số lợi ích của các thành phần chế độ xem, như đã nêu trong tài liệu của nó, bao gồm những lợi ích sau:

  • Chúng nhanh hơn ~ 10 lần so với phần mềm.
  • Chúng là các đối tượng Ruby; do đó, phương thức khởi tạo của họ xác định rõ ràng những gì cần thiết để hiển thị một khung nhìn. Điều này có nghĩa là chúng dễ hiểu hơn và dễ sử dụng hơn trong một số chế độ xem khác. Hơn nữa, các tiêu chuẩn chất lượng của mã Ruby có thể được thực thi, do đó giảm nguy cơ lỗi.
  • Chúng có thể được kiểm tra đơn vị thay vì các chế độ xem truyền thống của Rails, yêu cầu kiểm tra tích hợp cũng thực hiện các lớp định tuyến và bộ điều khiển ngoài chế độ xem.

Triển khai ViewComponent

ViewComponents là lớp con của ViewComponent::Base và sống trong app/components . Tên của chúng kết thúc bằng - Component và chúng phải được đặt tên cho những gì chúng hiển thị chứ không phải những gì chúng chấp nhận. Chúng tôi có thể tạo thành phần chế độ xem theo cách thủ công hoặc thông qua trình tạo thành phần, nhưng không thể không thêm đá quý vào tệp gem của chúng tôi và chạy bundle install đầu tiên.

gem "view_component", require: "view_component/engine"

Để sử dụng trình tạo, hãy chạy lệnh sau:

rails generate component <Component name> <arguments needed for initialization>

Ví dụ:nếu chúng tôi muốn tạo một thành phần chịu trách nhiệm hiển thị danh sách các khóa học trong lớp có sẵn trên nền tảng học tập, chúng tôi có thể sử dụng lệnh này:

rails g component Course course

Chúng tôi đang vượt qua course đối số với lệnh bởi vì chúng tôi sẽ khởi tạo đối tượng Ruby này với khóa học mà chúng tôi mong đợi nó hiển thị và chúng tôi đặt tên nó là Course bởi vì nó hiển thị một khóa học. Thật là trùng hợp!

Giới thiệu về ViewComponent Gem

Như chúng ta có thể thấy ở trên, thành phần và chế độ xem tương ứng của nó được tạo trong app/components cùng với một tệp thử nghiệm.

ViewComponent bao gồm các trình tạo mẫu cho erb , hamlslim công cụ mẫu nhưng sẽ mặc định thành bất kỳ công cụ mẫu nào được chỉ định trong config.generators.template_engine Tuy nhiên, bạn có thể chỉ ra công cụ mẫu ưa thích của mình bằng cách sử dụng như sau:

rails generate component Course course --template-engine <your template engine>

Hãy tiến hành tạo mô hình Khóa học của chúng tôi và một số khóa học để hiển thị.

rails g model Course title:string price:decimal location:string
rails db:migrate

Trong bảng điều khiển của chúng tôi, chúng tôi có thể nhanh chóng tạo hai khóa học mới:

Course.create(title: 'The Art of Learning', price: 125.00, location: 'Denmark')
Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')

course_component.rb tệp được tạo bằng phương thức khởi tạo tại chỗ, như được hiển thị bên dưới.

Giới thiệu về ViewComponent Gem

Chúng tôi cần tạo một bộ điều khiển khóa học định tuyến chúng tôi đến danh sách các khóa học.

rails g controller Courses index

Trong routes.rb của chúng tôi tệp, chúng tôi chỉ ra tuyến đường gốc của chúng tôi bằng cách thêm thông tin sau:

root 'courses#index'

Bây giờ chúng ta đã hoàn tất, bước tiếp theo là tạo chế độ xem. Điều này được thực hiện trong course_component.html.erb đã được tạo .

<div>
  <h2><%= @course.title %></h2>
  <h4><%=  number_to_currency(@course.price, :unit => "€") %></h4>
  <h4><%= @course.location %></h4>
</div>

Theo quan điểm của chúng tôi, chúng tôi hiển thị tên khóa học, giá cả và địa điểm bằng cách sử dụng @course biến, đã được xác định trong phương thức khởi tạo của CourseComponent của chúng tôi. Điều này tương tự như khi bạn tạo một biến trong phương thức bộ điều khiển và sau đó biến này có sẵn trong một dạng xem.

Biết cách bộ điều khiển hoạt động, chúng tôi sẽ được chuyển đến index.html.erb tương ứng của phương pháp chỉ mục của chúng tôi. Do đó, đây là nơi chúng tôi hiển thị thành phần của mình.

#app/views/courses/index.html.erb
<%= render(CourseComponent.new(course: Course.find(1))) %>

Như đã thấy ở trên, chúng tôi kết xuất một phiên bản mới của CourseComponent bằng cách khởi tạo nó với khóa học mà chúng tôi dự định nó sẽ hiển thị trong chế độ xem của nó. Khóa học này trở thành @course biến được cung cấp cho course_component.html.erb tệp.

Cũng có thể hiển thị thành phần này trực tiếp từ bộ điều khiển của chúng tôi, do đó bỏ qua chế độ xem tệp chỉ mục:

class CoursesController < ApplicationController
  def index
    render(CourseComponent.new(course: Course.find(1)))
  end
end

Bất kể bạn chọn phương pháp nào, điều này sẽ hiển thị trên máy chủ:

Giới thiệu về ViewComponent Gem

Nội dung bổ sung cũng có thể được chuyển tới thành phần theo một trong những cách sau:

<%= render(CourseComponent.new(course: Course.find(1))) do %>
  container
<% end %>
<%= render(CourseComponent.new(course: Course.find(1)).with_content("container")) %>

Trong tệp thành phần chế độ xem của chúng tôi, chúng tôi có thể đưa nội dung vào bất cứ nơi nào chúng tôi muốn. Trong trường hợp này, chúng tôi sẽ bao gồm nó dưới dạng một lớp bằng cách chỉnh sửa div của chúng tôi để trông giống như sau:

<div class=<%= content %>>

Tất cả các phương pháp hiển thị nội dung bổ sung ở trên mang lại hình ảnh bên dưới:

Giới thiệu về ViewComponent Gem

Hiển thị Bộ sưu tập

Điều gì sẽ xảy ra nếu chúng tôi muốn hiển thị toàn bộ danh sách các khóa học của mình? ViewComponent cung cấp một cách rất đơn giản để thực hiện việc này bằng cách sử dụng with_collection nhãn. Thay vì khởi tạo thành phần bằng .new , nó được khởi tạo bằng .with_collection và bộ sưu tập được chuyển cho nó dưới dạng một biến, như được hiển thị bên dưới.

CourseComponent.with_collection(Course.all)

Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Ngoài ra còn có một with_collection_parameter có sẵn thẻ trong trường hợp chúng tôi muốn giải quyết bộ sưu tập bằng một tên khác.

class CourseComponent < ViewComponent::Base
  with_collection_parameter :item

  def initialize(item:)
    @item = item
  end
end

Trong trường hợp trên, tham số khóa học được coi là item . Do đó, trong chế độ xem tương ứng, @course sẽ được thay thế bằng @item để mang lại kết quả tương tự.

Các thông số bổ sung cũng có thể được thêm vào bộ sưu tập. Các thông số này sẽ được hiển thị theo từng mục trong bộ sưu tập. Hãy thêm một Buy Me nhắn tin cho từng mục qua phương thức này.

#app/views/courses/index.html.erb
<%= render(CourseComponent.with_collection(Course.all, notice: "Buy Me")) %>
# app/components/course_component.rb
class CourseComponent < ViewComponent::Base
  with_collection_parameter :item
  def initialize(item:, notice:)
    @item = item
    @notice = notice
  end
end

Chúng tôi thêm một đoạn mới vào app/components/course_component.html.erb tệp để chỉ ra văn bản cho biến thông báo mới được thêm vào.

<p><a href='#'> <%= @notice %> </a></p>

Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Cuối cùng, trong bộ sưu tập, chúng tôi có một biến bộ đếm có thể được bật để đánh số các mục trong một chế độ xem. Nó được kích hoạt bằng cách thêm _counter vào tham số bộ sưu tập và cung cấp nó cho các chế độ xem thông qua phương thức khởi tạo.

#app/components/course_component.rb
def initialize(item:, notice:, item_counter:)
  @item = item
  @notice = notice
  @counter = item_counter
end

Theo quan điểm của chúng tôi, bên cạnh tiêu đề mặt hàng, chúng tôi thêm bộ đếm của chúng tôi:

<h2><%= @counter %>. <%= @item.title %></h2>

Hãy tạo khóa học thứ ba từ bảng điều khiển để hiểu rõ hơn về hiện tượng bộ đếm.

Course.create(title: 'Understanding Databases', price: '100', location: 'Amsterdam')

Điều này mang lại kết quả sau

Giới thiệu về ViewComponent Gem

Kết xuất có điều kiện

ViewComponent có render? hook, khi được sử dụng, sẽ xác định xem có nên hiển thị một chế độ xem hay không. Để thực hiện điều này, chúng tôi sẽ giảm giá 10% cho các khóa học có giá bằng hoặc lớn hơn 100 Euro. Hãy tạo một thành phần cho mục đích này.

rails generate component Discount item

Giới thiệu về ViewComponent Gem

Thành phần này đã được khởi tạo tự động với mặt hàng mà nó sẽ hiển thị giảm giá, như được thấy bên dưới.

Giới thiệu về ViewComponent Gem

Do đó, trong discount_component.html.erb tệp, chúng tôi thêm văn bản mà chúng tôi định hiển thị.

<p class="green"> A 10% discount is available on this course </p>

Đừng ngần ngại thêm lớp green vào tệp css của bạn và gán cho nó bất kỳ màu xanh nào bạn thích. Hơn nữa, trong discount_component.rb của chúng tôi , chúng tôi thêm render? để xác định thời điểm nên hiển thị thành phần này.

def render?
  @item.price >= 100
end

Bây giờ, chúng ta có thể tiếp tục và hiển thị thành phần chiết khấu trong chế độ xem hiển thị từng khóa học.

# app/components/course_component.html.erb
<%= render(DiscountComponent.new(item: @item)) %>

Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Điều đó thật tuyệt phải không?

Người trợ giúp

Trong các khung nhìn Rails truyền thống, chúng ta có thể dễ dàng bổ sung các trình trợ giúp của mình bằng cách gọi tên phương thức trong các khung nhìn của chúng tôi, nhưng nó hoạt động khác với các thành phần của khung nhìn. Trong các thành phần của khung nhìn, các phương thức trợ giúp không thể được gọi trực tiếp trong các khung nhìn nhưng có thể được đưa vào một thành phần. Chúng tôi đã có một courses_helper.rb tệp được tạo tự động khi CoursesController được tạo, vì vậy hãy tận dụng nó. Đầu tiên, hãy tạo một phương thức trợ giúp cho chúng ta biết có bao nhiêu người đã đăng ký một khóa học cho đến nay. Hãy làm cho giá trị bằng một phần tư giá :).

module CoursesHelper
  def count_enrollees(course)
    count = (course.price / 4).round()
    tag.p "#{count} enrollees so far"
  end
end

Tiếp theo, chúng tôi sẽ tạo một thành phần mà chúng tôi sẽ gọi trình trợ giúp. Đây là thành phần sẽ được hiển thị trong chế độ xem của chúng tôi. Trong đó, chúng tôi sẽ thêm một include , bao gồm trình trợ giúp và sau đó chúng ta có thể gọi bất kỳ phương thức nào trong trình trợ giúp trong thành phần này.

# app/components/enrollee_component.rb
class EnrolleeComponent < ViewComponent::Base
include CoursesHelper

  def total_enrollees(course)
    count_enrollees(course)
  end
end

Bước cuối cùng là thêm EnrolleeComponent vào dạng xem hiển thị các khóa học của chúng tôi.

# app/components/course_component.html.erb
<%= EnrolleeComponent.new.total_enrollees(@item) %>

Lưu ý rằng chúng tôi không sử dụng từ kết xuất cho EnrolleeComponent, vì nó không có chế độ xem và đầu ra của nó sẽ là của phương thức trợ giúp được gọi. Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Người trợ giúp có thể được sử dụng cho các biểu tượng, gravitar hoặc bất cứ thứ gì bạn có thể chọn. ViewComponent không thay đổi việc sử dụng trình trợ giúp; nó chỉ thay đổi cách chúng ta gọi chúng trong các thành phần của mình.

Phương thức before_render

ViewComponent cung cấp before_render phương thức có thể được gọi trước khi một thành phần được hiển thị. Hãy thêm một ngôi sao bên cạnh thông báo giảm giá của chúng tôi. Chúng tôi bắt đầu bằng cách thêm một phương thức trợ giúp tìm nạp ngôi sao; a star.png hình ảnh cũng đã được tải xuống và được đặt trong app/assets/images thư mục.

#app/helpers/courses_helper.rb
def star_icon
  image_tag("/assets/star.png", width: "1%")
end

Hãy thêm một before_render thành phần Giảm giá của chúng tôi gọi phương thức trợ giúp này.

# app/components/discount_component.rb
def before_render
  @star_icon = helpers.star_icon
end

Như chúng ta có thể thấy ở trên, một cách gọi người trợ giúp khác được giới thiệu. Người trợ giúp cũng có thể được gọi bằng cách sử dụng helpers.method trong tệp component.rb. Sau đó, trong phương thức kết xuất của chúng tôi cho Công ty giảm giá, chúng tôi nhập biểu tượng ngôi sao của chúng tôi, biểu tượng này hiện có sẵn thông qua @star_icon biến.

# app/components/discount_component.html.erb
<p class="green"> <%= @star_icon %> A 10% discount is available on this course </p>

Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Chúng tôi không nhất thiết phải sử dụng trình trợ giúp cho before_render phương pháp để làm việc. Tôi đã sử dụng trình trợ giúp để giới thiệu một cách tiếp cận khác để gọi các phương thức trợ giúp.

Bản xem trước

Giống như Action Mailer, ViewComponent giúp bạn có thể xem trước các thành phần. Điều này trước tiên phải được bật trong config/application.rb tệp.

config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"

Các thành phần xem trước nằm trong test/components/previews và có thể được sử dụng để xem trước một thành phần với một số đầu vào khác nhau được chuyển vào. Chúng tôi sẽ xem trước Thành phần chiết khấu của chúng tôi.

# test/components/previews/discount_component_preview.rb
class DiscountComponentPreview < ViewComponent::Preview
  def with_first_course
    render(DiscountComponent.new(item: Course.find(1)))
  end

  def with_second_course
    render(DiscountComponent.new(item: Course.find(2)))
  end
end

Hai phương pháp đã được thêm vào để xem trước Thành phần chiết khấu trong các tình huống khác nhau. Để xem phần này, hãy truy cập https://localhost:3000/rails/view_components , nơi chúng tôi tìm thấy tất cả các thành phần xem trước được tạo và phương thức của chúng. Chúng ta có thể nhấp vào bất kỳ thứ gì trong số chúng để xem chúng trông như thế nào, như hình dưới đây.

Giới thiệu về ViewComponent Gem

Như bạn có thể thấy trong video ở trên, khóa học đầu tiên hiển thị thành phần giảm giá, nhưng không có gì được hiển thị cho khóa học thứ hai. Bạn có biết tại sao điều này xảy ra không? render? kiểm tra phương pháp đã xảy ra. Kịch bản đầu tiên là khi giá vốn cao hơn 100 euro (khóa học đầu tiên), nhưng chi phí thấp hơn 100 euro cho khóa học thứ hai. Tên phương pháp không mang tính mô tả nhiều hơn để giúp bạn tìm ra nguyên nhân trước khi nó được đánh dấu ở đây :).

Xem trước có thể được bật hoặc tắt trong bất kỳ môi trường nào bằng cách sử dụng show_previews nhưng trong môi trường phát triển và thử nghiệm, chúng được bật theo mặc định.

# config/environments/test.rb
config.view_component.show_previews = false

Bao gồm JS VÀ CSS

Có thể bao gồm JavaScript và CSS cùng với các thành phần, đôi khi được gọi là nội dung hoặc tệp "sidecar". Đây vẫn là một tính năng thử nghiệm. Do đó, chúng tôi sẽ không đi sâu vào hoạt động bên trong của nó trong bài viết này, nhưng bạn có thể tìm thêm về tính năng ViewComponent này tại đây.

Mẫu

Mẫu của một thành phần dạng xem có thể được xác định theo một số cách. Tùy chọn đơn giản hơn là chèn chế độ xem và thành phần trong cùng một thư mục, như được hiển thị bên dưới.

Giới thiệu về ViewComponent Gem

Như chúng ta có thể thấy ở đây, chúng ta có mọi thành phần và chế độ xem trong app/components thư mục.

Một tùy chọn khác là đặt chế độ xem và các nội dung khác trong một thư mục con có cùng tên với thành phần. Do đó, trong app/components thư mục, chúng ta có component.rb tệp, nơi chứa thành phần và sau đó là course_component riêng biệt thư mục chứa chế độ xem course_component.html.erb và mọi nội dung khác liên quan đến course_component.

Giới thiệu về ViewComponent Gem

Để tạo các tệp thành phần theo cách này từ dòng lệnh, --sidecar cờ là bắt buộc:

rails g component Example name  --sidecar

Điều này cho phép bạn thêm các tệp css và js của mình vào thư mục thành phần .ViewComponents cũng có thể hiển thị mà không cần tệp mẫu bằng cách xác định lệnh gọi call phương pháp. Ví dụ về điều này được cung cấp trong phần tiếp theo, nơi chúng ta thảo luận về vị trí .

Slots

Nhiều khối nội dung có thể được chuyển đến một ViewComponent duy nhất bằng cách sử dụng vị trí . Tương tự với has_onehas_many các thuộc tính trong mô hình Rails, các vị trí được xác định bằng renders_onerenders_many :

  • renders_one xác định một vị trí sẽ được hiển thị nhiều nhất một lần cho mỗi thành phần:renders_one:header.
  • renders_many xác định một vị trí có thể được hiển thị nhiều lần cho mỗi thành phần:renders_many:title.

Hãy tưởng tượng rằng chúng ta muốn có một trang hiển thị tiêu đề và tiêu đề của tất cả các khóa học mà chúng ta có sẵn; điều này có thể đạt được bằng cách sử dụng vị trí . Hãy tạo ListComponent , sẽ chứa tiêu đề chỉ được hiển thị một lần và TitleComponent , hiển thị nhiều tiêu đề.

#app/components/list_component.rb
class ListComponent < ViewComponent::Base
  renders_one :header, "HeaderComponent"
  # `HeaderComponent` is defined within this component, so we refer to it using a string.
  renders_many :titles, TitleComponent
  # `titleComponent` will be defined in another file, so we can refer to it by class name.
  class HeaderComponent < ViewComponent::Base
    def call
      content_tag :h1, content
    end
  end
end

Trong thành phần ở trên, chúng tôi đã nói rằng tiêu đề được hiển thị một lần, nhưng tiêu đề được hiển thị nhiều lần, vì trang này sẽ chứa nhiều tiêu đề. Chúng tôi cũng đã định nghĩa HeaderComponent trong ListComponent. Có, điều này có thể thực hiện được với ViewComponent; một lớp có thể được định nghĩa trong một lớp khác. Cũng hãy lưu ý đến phương thức gọi được thảo luận trước đó trong phần Mẫu và cách nó được sử dụng trong HeaderComponent để hiển thị thẻ h1, do đó loại bỏ nhu cầu về chế độ xem tương ứng (tệp html.erb). Tệp HTML tương ứng cho ListComponent sẽ chứa những thứ sau;

#app/components/list_component.html.erb
<div>
  <%= header %> <!-- renders the header component -->
  <% titles.each do |title| %>
    <div>
      <%= title %> <!-- renders an individual course title -->
    </div>
  <% end %>
</div>

Trong tệp html, chúng tôi đã bao gồm tiêu đề, lặp lại qua tất cả các tiêu đề được chuyển vào thành phần và hiển thị chúng. Như bạn có thể thấy, chúng tôi không phải chỉ định tên của thành phần sẽ được hiển thị trong tệp dạng xem danh sách; khe cắm của chúng tôi đã giải quyết vấn đề đó. Do đó, chúng tôi chỉ xác định chúng là headertitle .

Bước tiếp theo là tạo TitleComponent của chúng tôi và tệp HTML tương ứng của nó, vì đây là những gì sẽ được hiển thị cho mọi tiêu đề được chuyển qua.

# app/components/title_component.rb
class TitleComponent < ViewComponent::Base
  def initialize(title:)
    @title = title
  end
end
# app/components/title_component.html.erb
<div>
  <h3> <%= @title %> </h3>
</div>

Cuối cùng, trong index.html của chúng tôi , hãy tạm thời xóa những gì chúng ta có và thay thế nó bằng kết xuất ListComponent.

#app/views/courses/index.html.erb
<%= render ListComponent.new do |c| %>
  <% c.header do %>
  <%= link_to "List of Available Courses", root_path %>
  <% end %>
  <%= c.title(title: "First title") %>
  <%= c.title(title: "Second title!") %>
<% end %>

Giới thiệu về ViewComponent Gem

Bây giờ, hãy chuyển các khóa học của chúng tôi vào chế độ xem này như một bộ sưu tập. Để chuyển một bộ sưu tập vào một vị trí, chúng ta phải truyền bộ sưu tập dưới dạng một mảng các đối tượng có chứa biến cần thiết để khởi tạo. Như chúng ta có thể thấy, mọi khóa học được truyền vào phải được khởi tạo bằng đối số tiêu đề. Chúng tôi có thể trích xuất tiêu đề của tất cả các khóa học trong db của chúng tôi thành một mảng băm và hiển thị nó.

Giới thiệu về ViewComponent Gem

Giờ đây, chúng tôi có thể thay thế danh sách một số tiêu đề bằng một c.titles duy nhất cho một bộ sưu tập và chuyển nó vào hàm băm tiêu đề của chúng tôi, chúng tôi xác định bằng cách sử dụng biến course_titles .

# app/views/courses/index.html.erb
<% course_titles = Course.all.pluck(:title).map { |title| {title: title}} %>

<% c.titles(course_titles) %>

Điều này dẫn đến kết quả sau:

Giới thiệu về ViewComponent Gem

Đây chính xác là cách các khe hoạt động:hiển thị một số thành phần trong một ViewComponent duy nhất. Các vị trí có thể được hiển thị theo một số cách khác và bạn có thể tìm thêm thông tin tại đây.

Kiểm tra

Kiểm tra các thành phần chế độ xem được thực hiện bằng cách yêu cầu "view_component / test_case" trong tệp kiểm tra và sử dụng render_inline trình trợ giúp kiểm tra để các xác nhận được thực hiện dựa trên kết quả được hiển thị. Hãy bắt đầu bằng cách thử nghiệm Thành phần Giảm giá của chúng tôi.

require "test_helper"
require "view_component/test_case"

class DiscountComponentTest < ViewComponent::TestCase
  def test_render_component
    render_inline(DiscountComponent.new(item: "my item"))
  end
end

Khi chúng tôi chạy kiểm tra này bằng lệnh rails test test/components/discount_component_test.rb , chúng tôi gặp lỗi sau:

Giới thiệu về ViewComponent Gem

Điều này chứng minh cho chúng tôi thấy rằng bài kiểm tra đang đi đến đúng thành phần nhưng thiếu một giá đỡ phù hợp, vì mục đó phải là một khóa học có thuộc tính giá chứ không phải là một chuỗi như chúng tôi đã vượt qua. Nó cũng cho chúng ta biết rằng có một render? phương thức được kiểm tra trước khi thành phần này hiển thị. Hãy chuyển các biến phù hợp ngay bây giờ.

def test_render_component
  course = Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
end

Điều này chạy thành công. Hãy tiến hành thêm các xác nhận vào bài kiểm tra này.

def test_render_component
  course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
  assert_selector 'p[class="green"]'
  assert_text "10% discount"
end

Quá trình kiểm tra này cũng vượt qua, thông báo rằng có một điều kiện kết xuất cho thành phần này. Tuy nhiên, đừng lo lắng vì ViewComponent cũng cung cấp một cách để kiểm tra xem một thành phần không được hiển thị hay không bằng cách sử dụng refute_component_rendered . Chúng tôi có thể kiểm tra điều này bằng một khóa học có giá dưới 100 euro.

def test_component_not_rendered
  course = Course.create(title: 'Organizing your Time', price: 55.00, location: 'London')
  render_inline(DiscountComponent.new(item: course))
  refute_component_rendered
end

Bài kiểm tra này cũng vượt qua.

Hãy viết một bài kiểm tra khác cho CourseComponent của chúng tôi để kiểm tra xem nó có hiển thị tất cả các thành phần được lồng trong nó hay không.

require "test_helper"
require "view_component/test_case"

class CourseComponentTest < ViewComponent::TestCase
  def test_component_renders_all_children
    course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
    render_inline(CourseComponent.new(item: course, notice: 'A new test', item_counter: 1))
    assert_selector("h2", text: "Organizing your Time")
    assert_selector("h4", text: "€155.00")
    assert_selector("h4", text: "London")
    assert_text("enrollees")
    assert_text("discount")
  end
end

Thử nghiệm này cũng vượt qua. Nó kiểm tra rằng các thành phần Người đăng ký và Chiết khấu cũng hiển thị đúng cách.

Nhớ lại rằng chúng ta có một thành phần vị trí và như thể hiện trong hình ảnh bên dưới, nó hiển thị một tiêu đề và nhiều tiêu đề.

Giới thiệu về ViewComponent Gem

Để kiểm tra điều này, chúng tôi chuyển cho thành phần một khối mã chứa tiêu đề và tiêu đề mà nó sẽ hiển thị và sau đó chúng tôi có thể khẳng định với thành phần được kết xuất.

require "test_helper"
require "view_component/test_case"

class ListComponentTest < ViewComponent::TestCase
  def test_renders_slots_with_content
  render_inline(ListComponent.new) do |component|
  component.header { "A Test List" }
  component.titles [{title: 'Test title 1'}, {title: 'Test title 2'}]
  end

  assert_selector("h1", text: "A Test List")

  assert_text("Test title 1")
  assert_text("Test title 2")
  end
end

Bài kiểm tra này cũng vượt qua :).

Kiểm tra Rspec

Ngoài tất cả những gì đã nói ở trên về kiểm tra, nếu khung kiểm tra ưa thích là RSpec, một số cấu hình bổ sung phải được thực hiện để kích hoạt RSpec cho ViewComponents.

# spec/rails_helper.rb
require "view_component/test_helpers"
require "capybara/rspec"

RSpec.configure do |config|
  config.include ViewComponent::TestHelpers, type: :component
  config.include Capybara::RSpecMatchers, type: :component
end

Bài kiểm tra chiết khấu của chúng tôi có thể được viết lại và kiểm tra lại bằng Rspec, như được hiển thị bên dưới:

require "rails_helper"

RSpec.describe DiscountComponent, type: :component do

  it "renders the component correctly" do
    course = Course.create(title: 'Organizing your Time', price: 155.00, location: 'London')
    render_inline(DiscountComponent.new(item: course))
    expect(rendered_component).to have_css "p[class='green']", text: "10% discount"
    expect(rendered_component).to have_css "img[src*='/assets/star.png']"
  end
end

Thử nghiệm này vượt qua một cách thanh lịch. Đúng vậy, chúng ta có thể thấy biểu tượng ngôi sao của mình.

Kết luận

Việc viết một số thành phần chế độ xem cho ứng dụng Rails của bạn không chỉ làm cho mã của bạn dễ đọc hơn và ít bị lỗi do các biến chứng không mong muốn mà còn giúp bạn có thể kiểm tra các chế độ xem của mình một cách riêng biệt và không chỉ trong các yêu cầu HTTP. Các thành phần của chế độ xem dễ dàng đưa vào ứng dụng Rails hiện có và tốt nhất là bắt đầu với các chế độ xem hầu như được sử dụng lại. Với mọi thứ đã học được cho đến nay, đây sẽ là một nhiệm vụ dễ dàng. Tuy nhiên, nếu bạn muốn biết thêm thông tin về ViewComponent, đừng ngần ngại xem qua tài liệu của nó hoặc thông tin về RubyDoc.