2008-09-18 26 views
52

Tôi có một bảng cơ sở dữ liệu đơn giản gọi là "Entries":trong đường ray, làm thế nào để trả lại hồ sơ như một tập tin csv

class CreateEntries < ActiveRecord::Migration 
    def self.up 
    create_table :entries do |t| 
     t.string :firstName 
     t.string :lastName 
     #etc. 
     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :entries 
    end 
end 

Làm thế nào để viết một handler mà sẽ trở lại với nội dung của bảng Entries như một CSV tệp (lý tưởng theo cách nó sẽ tự động mở trong Excel)?

class EntriesController < ApplicationController 

    def getcsv 
    @entries = Entry.find(:all) 

    # ??? NOW WHAT ???? 

    end 

end 
+0

Ít nhất trong các phiên bản gần đây của Rails, bạn cũng có thể sử dụng 'Entry. tất cả' thay thế. –

Trả lời

22

Có plugin được gọi là FasterCSV xử lý tuyệt vời này.

+29

Lưu ý rằng ruby> = 1,9, FasterCSV hiện là thư viện CSV chuẩn và chỉ được gọi là CSV. – kdt

+0

khóa là 'yêu cầu' csv'', hãy xem https://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html – mb21

7

Hãy xem đá quý FasterCSV.

Nếu tất cả những gì bạn cần là hỗ trợ excel, bạn cũng có thể xem xét việc tạo một xls trực tiếp. (Xem bảng tính Excel ::)

gem install fastercsv 
gem install spreadsheet-excel 

Tôi tìm thấy những lựa chọn tốt cho việc mở tập tin csv trong Windows Excel:

FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... } 

Đối với phần ActiveRecord, một cái gì đó như thế này sẽ làm:

CSV_FIELDS = %w[ title created_at etc ] 
FasterCSV.generate do |csv| 
    Entry.all.map { |r| CSV_FIELDS.map { |m| r.send m } }.each { |row| csv << row } 
end 
2

Bạn cần đặt tiêu đề Kiểu nội dung trong phản hồi của mình, sau đó gửi dữ liệu. Content_Type: application/vnd.ms-excel nên làm thủ thuật.

Bạn cũng có thể muốn đặt tiêu đề Nội dung-Bố trí sao cho nó trông giống như tài liệu Excel và trình duyệt chọn tên tệp mặc định hợp lý; đó là một cái gì đó như Content-Disposition: attachment; filename = "# {suggest_name} .xls"

Tôi khuyên bạn nên sử dụng đá quý ruby ​​fastcsv để tạo CSV của mình, nhưng cũng có csv được tích hợp sẵn. Mẫu mã fastercsv (từ tài liệu của đá quý) trông như thế này:

csv_string = FasterCSV.generate do |csv| 
    csv << ["row", "of", "CSV", "data"] 
    csv << ["another", "row"] 
# ... 
end 
+0

Cảm ơn loại Nội dung tối nghĩa! Tôi không thực sự chắc chắn nếu nó sẽ được Excel cuối cùng, nhưng đó là tốt để biết. – Eric

87

FasterCSV chắc chắn là con đường để đi, nhưng nếu bạn muốn để phục vụ trực tiếp từ ứng dụng Rails của bạn, bạn sẽ muốn thiết lập một số các tiêu đề phản hồi cũng vậy.

tôi giữ một phương pháp xung quanh để thiết lập tên tập tin và các tiêu đề cần thiết:

def render_csv(filename = nil) 
    filename ||= params[:action] 
    filename += '.csv' 

    if request.env['HTTP_USER_AGENT'] =~ /msie/i 
    headers['Pragma'] = 'public' 
    headers["Content-type"] = "text/plain" 
    headers['Cache-Control'] = 'no-cache, must-revalidate, post-check=0, pre-check=0' 
    headers['Content-Disposition'] = "attachment; filename=\"#{filename}\"" 
    headers['Expires'] = "0" 
    else 
    headers["Content-Type"] ||= 'text/csv' 
    headers["Content-Disposition"] = "attachment; filename=\"#{filename}\"" 
    end 

    render :layout => false 
end 

Sử dụng mà làm cho nó dễ dàng để có một cái gì đó như thế này trong bộ điều khiển của tôi:

respond_to do |wants| 
    wants.csv do 
    render_csv("users-#{Time.now.strftime("%Y%m%d")}") 
    end 
end 

Và có một cái nhìn trông giống như sau: (generate_csv từ FasterCSV)

UserID,Email,Password,ActivationURL,Messages 
<%= generate_csv do |csv| 
    @users.each do |user| 
    csv << [ user[:id], user[:email], user[:password], user[:url], user[:message] ] 
    end 
end %> 
+0

Hmm, tôi nghĩ tôi đã làm xong cho đến khi tôi thấy câu trả lời của bạn! Cảm ơn cho các chi tiết tiêu đề, tôi sẽ nhớ những người trong trường hợp tôi gặp rắc rối với những gì tôi đang sử dụng cho đến nay. – Eric

+8

Như đã đề cập ở trên, FasterCSV chỉ là CSV từ ruby ​​1.9 trở lên. Phương thức gererate_csv giờ đây là CSV.generate. –

+4

Thêm .html_safe vào cuối khối generate_csv/CSV.generate sẽ làm cho nó để bất kỳ dấu phẩy nào trong dữ liệu được xử lý đúng cách. Nếu không có cuộc gọi này, tệp csv của tôi có một số " " trong đó. – stcorbett

24

Tôi đã chấp nhận (và đã bỏ phiếu!) Câu trả lời của @ Brian, trước tiên đã chỉ tôi đến với FasterCSV. Sau đó, khi tôi googled để tìm đá quý, tôi cũng tìm thấy một ví dụ khá hoàn chỉnh tại this wiki page. Đặt chúng lại với nhau, tôi giải quyết trên đoạn mã sau.

Bằng cách này, các lệnh để cài đặt các viên ngọc là: sudo gem install fastercsv (tất cả chữ thường)

require 'fastercsv' 

class EntriesController < ApplicationController 

    def getcsv 
     entries = Entry.find(:all) 
     csv_string = FasterCSV.generate do |csv| 
      csv << ["first","last"] 
      entries.each do |e| 
       csv << [e.firstName,e.lastName] 
      end 
      end 
      send_data csv_string, :type => "text/plain", 
      :filename=>"entries.csv", 
      :disposition => 'attachment' 

    end 


end 
+5

Tôi khuyên bạn nên di chuyển thế hệ CSV sang chế độ xem: đó là logic trình bày nhiều hơn mức bạn thường muốn trong bộ điều khiển. –

+0

Bạn có thể muốn đặt loại thành 'text/csv'. Nếu không, safari sẽ lưu nó dưới dạng 'entries.csv.txt' – silasjmatson

24

Một cách khác để làm điều này mà không sử dụng FasterCSV:

Yêu cầu csv của ruby thư viện trong một tập tin khởi tạo như config/initializers/dependencies.rb

require "csv" 

như một số nền tảng mã sau đây là dựa trên số Ryan Bate's Advanced Search Form tạo tài nguyên tìm kiếm. Trong trường hợp của tôi, phương thức hiển thị của tài nguyên tìm kiếm sẽ trả về kết quả của tìm kiếm đã lưu trước đó. Nó cũng đáp ứng với csv và sử dụng mẫu xem để định dạng đầu ra mong muốn.

def show 
    @advertiser_search = AdvertiserSearch.find(params[:id]) 
    @advertisers = @advertiser_search.search(params[:page]) 
    respond_to do |format| 
     format.html # show.html.erb 
     format.csv # show.csv.erb 
    end 
    end 

tập tin Các show.csv.erb trông giống như sau:

<%- headers = ["Id", "Name", "Account Number", "Publisher", "Product Name", "Status"] -%> 
<%= CSV.generate_line headers %> 
<%- @advertiser_search.advertisers.each do |advertiser| -%> 
<%- advertiser.subscriptions.each do |subscription| -%> 
<%- row = [ advertiser.id, 
      advertiser.name, 
      advertiser.external_id, 
      advertiser.publisher.name, 
      publisher_product_name(subscription), 
      subscription.state ] -%> 
<%= CSV.generate_line row %> 
<%- end -%> 
<%- end -%> 

Trên phiên bản html của trang báo cáo tôi có một liên kết để xuất báo cáo rằng người dùng đang xem. Sau đây là liên kết_để trả về phiên bản csv của báo cáo:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %> 
+5

Đừng quên sử dụng '<% = CSV.generate_line (hàng) .html_safe%>' nếu bạn đang sử dụng đường ray 3, để tránh các ký tự thoát. – dombesz

+6

Giải pháp này hoạt động tốt nhưng tôi phải thay đổi cài đặt cuộc gọi CSV.generate_line: row_sep thành không. Thay đổi này loại bỏ các dòng trống không mong muốn khỏi phản hồi. Code: '<% = CSV.generate_line row, {: row_sep => nil}%>' –

+2

Để thêm vào nhận xét của Wilson, Heroku (stacked cedar -beta) sẽ chèn các dòng trống vào các tệp csv trừ khi bạn nói rõ ràng là không với ': row_sep => nil'. – nslocum

2

Cách tiếp cận sau đây hoạt động tốt cho trường hợp của tôi và khiến trình duyệt mở ứng dụng thích hợp cho loại CSV sau khi tải xuống.

def index 
    respond_to do |format| 
    format.csv { return index_csv } 
    end 
end 

def index_csv 
    send_data(
    method_that_returns_csv_data(...), 
    :type => 'text/csv', 
    :filename => 'export.csv', 
    :disposition => 'attachment' 
) 
end 
1

thử một viên ngọc đẹp để tạo CSV từ Rails https://github.com/crafterm/comma

+1

Câu trả lời hay nhưng để làm cho nó trở nên tuyệt vời, có lẽ bạn có thể giải thích tại sao viên đá quý này (trái với những người khác) –

0

Hãy nhìn vào viên ngọc CSV Shaper.

https://github.com/paulspringett/csv_shaper

Nó có DSL đẹp và hoạt động thực sự tốt với các mô hình Rails. Nó cũng xử lý các tiêu đề phản hồi và cho phép tùy chỉnh tên tệp.

0

Nếu bạn chỉ đơn giản là muốn có được cơ sở dữ liệu csv mình từ giao diện điều khiển, bạn có thể làm như vậy trong một vài dòng

tags = [Model.column_names] 
rows = tags + Model.all.map(&:attributes).map(&:to_a).map { |m| m.inject([]) { |data, pair| data << pair.last } } 
File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join(""))} 
Các vấn đề liên quan