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 Product có id 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 title và updated để 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> và <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_id là 1. 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.
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.
















