Rails – Xây dựng tính năng RSS

4.8/5 - (6 votes)

RSS là công nghệ hỗ trợ người dùng cập nhật nội dung từ website mà không cần phải vào trang web. Cách hoạt động thì đơn giản là website sẽ tạo ra một file có định dạng XML rồi trả về cho người dùng, người dùng sẽ dùng một phần mềm để đọc file đó.

RSS cũng có nhiều phiên bản khác nhau, phổ biến nhất là RSS 1.0, RSS 2.0 và Atom. Cái nào cũng có ưu/nhược điểm riêng và đều được sử dụng rộng rãi, có website dùng cả 3 phiên bản.

Riêng Ruby có thư viện hỗ trợ tạo file RSS ở 3 phiên bản trên và các phiên bản khác nhỏ lẻ khác. Rails cũng có hàm tạo RSS dựa trên thư viện của Ruby, và mặc định Rails chọn phiên bản Atom.

Chúng ta sẽ tạo một file Atom hiển thị những đơn hàng đã mua sản phẩm có id bất kỳ.

Định nghĩa Action

Đầu tiên chúng ta định nghĩa phương thức who_bought trong lớp ProductsController như sau:

class ProductsController < ApplicationController
    .
    .
    .
    def who_bought 
        @product = Product.find(params[:id]) 
        respond_to do |format|
            format.atom
            format.xml { render :xml => @product }
        end
    end
    .
    .
    .
end

Phương thức này sẽ được gọi từ URL là /products/<id>/who_bought.atom . Ở đây chúng ta lấy đối tượng Productid tương ứng trong tham số gửi lên. Sau đó gọi hàm format.atom, hàm này sẽ chạy đoạn code có trong file <tên_phương_thức>.atom.builder nằm trong thư mục app/views/<tên model> dùng để tạo dữ liệu Atom, tức là ở đây sẽ gọi tới file who_bought.atom.builder trong thư mục app/views/products. Chúng ta truyền vào file này biến @product đã tạo ra ở trên trong phương thức format.xml.

Tạo dữ liệu Atom

Tiếp theo chúng ta tạo file who_bought.atom.builder trong thư mục app/views/products có nội dung như sau:

atom_feed do |feed|
    feed.title "Who bought #{@product.title}" 
 
    latest_order = @product.orders.sort_by(&:updated_at).last
    feed.updated(latest_order && latest_order.updated_at)
 
    @product.orders.each do |order|
        feed.entry(order) do |entry|
            entry.title "Order #{order.id}"
            entry.summary :type => 'xhtml' do |xhtml|
                xhtml.p "Shipped to #{order.address}"
 
                xhtml.table do
                    xhtml.tr do
                        xhtml.th 'Product'
                        xhtml.th 'Quantity'
                        xhtml.th 'Total Price'
                    end
 
                    order.line_items.each do |item|
                        xhtml.tr do
                            xhtml.td item.product.title
                            xhtml.td item.quantity
                            xhtml.td number_to_currency item.total_price
                        end
                    end
 
                    xhtml.tr do
                        xhtml.th 'Total', :colspan => 2
                        xhtml.th number_to_currency order.line_items.map(&:total_price).sum
                    end
                end
                xhtml.p "Paid by #{order.pay_type}"
            end 
    
            entry.author do |author|
                entry.name order.name
                entry.email order.email
            end
        end
    end
end

Hàm atom_feed là hàm helper tạo ra code XML theo định dạng Atom.

atom_feed do |feed|
...
end

Hàm này tạo ra một đối tượng ActionView::Helpers::AtomFeedHelper::AtomFeedBuilder, ở đây là biến feed.

feed.title "Who bought #{@product.title}" 
 
latest_order = @product.orders.sort_by(&:updated_at).last
feed.updated(latest_order && latest_order.updated_at)

Đầu tiên chúng ta gọi phương thức titleupdated để thiết lập tiêu đề và thời gian tạo gần đây nhất bằng cách lấy thời gian trong thuộc tính updated_at của bản ghi Order cuối cùng. Nếu không tìm thấy thì Rails sẽ lấy thời gian là giờ hiện tại trên máy. Hai phương thức này sẽ tạo thẻ <entry><title> trong file Atom.

@product.orders.each do |order|
    feed.entry(order) do |entry|
    ...
    end
end

Tiếp theo chúng ta lặp từng bản ghi Order, cứ mỗi lần lặp thì chúng ta gọi phương thức feed.entry. Phương thức này nhận vào một đối tượng bất kỳ và tạo ra biến ActionView::Helpers::AtomFeedHelper::AtomBuilder, ở đây là biến entry.

Chúng ta dùng biến entry này để tạo các thẻ html như bình thường. Bạn có thể dựa vào code là có thể tự đoán phương thức nào tạo thẻ nào rồi.

Thiết lập mối quan hệ

Tuy nhiên chúng ta chưa định nghĩa mối quan hệ giữa một đối tượng Product và một đối tượng Order. Nhưng một đối tượng Order lại chứa nhiều đối tượng LineItem, một đối tượng Product cũng có nhiều đối tượng LineItem, do đó chúng ta có thể liên kết đối tượng Product với đối tượng Order thông qua đối tượng LineItem như sau:

class Product < ActiveRecord::Base
    validates :title, :description, :image_url, :presence => true
    validates :price, :numericality => {:greater_than_or_equal_to => 1.0}
    validates :title, :uniqueness => true
    validates :image_url, :format => {
        :with => %r{\.(gif|jpg|png)\Z}i,
        :message => 'Chi nhan file GIF, JPG, PNG'
    }
 
    has_many :line_items
    has_many :orders, :through => :line_items
    before_destroy :check_if_has_line_item
 
private
 
    def check_if_has_line_item
        if line_items.empty?
            return true
        else
            errors.add(:base, 'This product has a LineItem')
            return false
        end
    end
end

Routing

Cuối cùng chúng ta điều hướng URL tới phương thức who_bought như sau:

Rails.application.routes.draw do
    resources :orders
    resources :line_items
    resources :carts
    get 'store/index'

    resources :products do 
        get :who_bought, :on => :member
    end
 
    root :to => 'store#index' 
end

Nếu bạn còn nhớ thì hàm resources sẽ tự động định nghĩa 7 URL vào 7 phương thức CRUD cơ bản.

Rails cho phép chúng ta điều hướng thêm vào sau các URL có sẵn, bằng cách khai báo thêm khối lệnh do...end sau phương thức resources và khai báo các dòng routing trong đó.

resources :products do
    get :who_bought, :on => :member
end

Dòng code trên sẽ gắn URL /who_bought vào URL của các phương thức đã định nghĩa trước đó, tức là Rails sẽ hiểu các URL như /products/1/who_bought. Và gửi tới phương thức who_bought trong lớp ProductsController.

Vậy là xong, bạn có thể chạy server và trỏ vào URL như /products/1/who_bought.atom là sẽ có đoạn code XML hiển thị danh sách các đơn hàng có sản phẩm có product_id1. Lưu ý là vì URL /who_bought trả về nội dung Atom chứ không phải HTML như bình thường nên khi trỏ thì chúng ta thêm đuôi .atom ở cuối URL.

capture

Nếu muốn bạn có thể dùng các phần mềm đọc tin RSS để đọc file Atom này cũng được. Dưới đây là hình khi dùng RSS Feed Reader, đây là một extension của trình duyệt Chrome.

bbbcapture

0 0 votes
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments