Export file CSV theo mô hình MVC
Bài đăng này đã không được cập nhật trong 3 năm
Như tiêu đề, hôm nay mình xin giới thiệu cách export file CSV theo chuẩn MVC cho những bạn chưa biết . Trước hết xin nói về cách mà trước đây đa số mọi người vẫn đùng như sau:
users_controller.rb
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html
format.csv { send_data @users.to_csv, filename: "users-#{Date.today}.csv" }
end
end
user.rb
class User < ActiveRecord::Base
def self.to_csv
attributes = %w{id email name}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |user|
csv << attributes.map{ |attr| user.send(attr) }
end
end
end
def name
"#{first_name} #{last_name}"
end
end
Và link gọi action sẽ có dạng như sau:
link_to("Export user to csv", users_path(format: :csv))
Với cách trên ta có thể thấy sự thiếu thống nhất trong chuẩn MVC và resful.
Action index
trong resful được hiểu là sẽ hiển thị toàn bộ users trong view.
Và theo MVC thì controller có nhiệm vụ lấy dữ liệu từ database chuyển cho view hiển thị. View hiển thị như thế nào thì sẽ được thể hiện trong file view tương ứng. Trong cách làm trên thì function to_csv
thể hiện việc hiển thị data lại được quy định trong model và hoàn toàn không có file view tương ứng.
Vậy để khắc phục những điều trên mình xin giới thiệu cách làm sau rõ ràng hơn.
book.rb
require 'csv'
class Book < ActiveRecord::Base
end
** books_controller.rb**
def index
respond_to do |format|
format.html do
@books = Book.all
end
format.csv do
filename = "Book_#{Time.now.to_i}.csv"
headers['Content-Disposition'] = "attachment; filename=#{filename}"
headers['Content-Type'] ||= 'text/csv'
@books = Book.all
end
end
end
Trong controller trên ta khai báo thông tin của file csv filename
, headers['Content-Disposition']
, headers['Content-Type']
và gửi data sang view bằng biến @books
Tiếp tục ta tạo 1 file index.csv
tương ứng để sắp xếp dữ liêu trong file csv nội dung như sau:
index.csv.slim
ruby:
attributes = ["id", "title", "author", "price"]
= CSV.generate_line attributes
- @books.each do |book|
- record = attributes.map { |attribute| book.send(attribute) }
= CSV.generate_line record
Đặt link export vào trang index tương tự như phần trên:
index.html.slim
= link_to 'export to csv', books_path(format: :csv)
Khi bấm vào link này ta sẽ thu được file csv như sau:
Như vậy ta có thể dễ dàng control việc sắp xếp dữ liệu và luồng xử lý với action tuơng ứng.
Toàn bộ code các bạn có thể xem tại đây
HAPPY CODING )
All rights reserved