في Rails، كيفية إرجاع السجلات كملف CSV
-
01-07-2019 - |
سؤال
لدي جدول قاعدة بيانات بسيط يسمى "الإدخالات":
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
كيف أكتب معالجًا يقوم بإرجاع محتويات جدول الإدخالات كملف CSV (من الأفضل أن يتم فتحه تلقائيًا في Excel)؟
class EntriesController < ApplicationController
def getcsv
@entries = Entry.find( :all )
# ??? NOW WHAT ????
end
end
المحلول
يوجد مكون إضافي يسمى FasterCSV يتعامل مع هذا الأمر بشكل رائع.
نصائح أخرى
أسرعCSV هو بالتأكيد الطريق الصحيح، ولكن إذا كنت تريد تقديمه مباشرة من تطبيق Rails الخاص بك، فستحتاج إلى إعداد بعض رؤوس الاستجابة أيضًا.
أحتفظ بطريقة لإعداد اسم الملف والرؤوس الضرورية:
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
يؤدي استخدام ذلك إلى تسهيل الحصول على شيء كهذا في وحدة التحكم الخاصة بي:
respond_to do |wants|
wants.csv do
render_csv("users-#{Time.now.strftime("%Y%m%d")}")
end
end
ولديك وجهة نظر تبدو مثل هذا:(generate_csv
من 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 %>
لقد قبلت (وصوتت!) إجابة @Brian، لتوجيهي أولاً إلى FasterCSV.ثم عندما بحثت في Google للعثور على الجوهرة، وجدت أيضًا مثالًا كاملاً إلى حد ما على صفحة الويكي هذه.بتجميعهم معًا، استقريت على الكود التالي.
بالمناسبة، أمر تثبيت الجوهرة هو:Sudo GEM تثبيت FasterCSV (جميع الحالات السفلية)
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
هناك طريقة أخرى للقيام بذلك دون استخدام FasterCSV:
اطلب مكتبة روبي CSV في ملف مُهيئ مثل config/initializers/dependeency.rb
require "csv"
كبعض الخلفية، يستند الكود التالي إلى نموذج البحث المتقدم لـ Ryan Bate الذي ينشئ مورد بحث.في حالتي، ستعيد طريقة العرض لمورد البحث نتائج البحث المحفوظ مسبقًا.كما أنه يستجيب لملف CSV، ويستخدم قالب عرض لتنسيق الإخراج المطلوب.
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
يبدو الملف show.csv.erb كما يلي:
<%- 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 -%>
في نسخة html من صفحة التقرير لدي رابط لتصدير التقرير الذي يشاهده المستخدم.ما يلي هو link_to الذي يُرجع نسخة CSV من التقرير:
<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
نلقي نظرة على أسرعCSV جوهرة.
إذا كان كل ما تحتاجه هو دعم Excel، فقد تفكر أيضًا في إنشاء ملف XLS مباشرةً.(راجع جدول البيانات::Excel)
gem install fastercsv
gem install spreadsheet-excel
أجد هذه الخيارات جيدة لفتح ملف CSV في Windows Excel:
FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... }
أما بالنسبة للجزء ActiveRecord، فإن شيئًا كهذا سيفي بالغرض:
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
تحتاج إلى تعيين رأس نوع المحتوى في إجابتك، ثم إرسال البيانات.نوع المحتوى:يجب أن يقوم application/vnd.ms-excel بالمهمة.
قد ترغب أيضًا في تعيين رأس ترتيب المحتوى بحيث يبدو كمستند Excel، ويختار المتصفح اسم ملف افتراضيًا معقولًا؛هذا شيء مثل التصرف في المحتوى:مرفق؛اسم الملف = "#{suggested_name}.xls"
أقترح استخدام Fastcsv Ruby Gem لإنشاء ملف CSV الخاص بك، ولكن هناك أيضًا ملف CSV مدمج.يبدو نموذج التعليمات البرمجية Fastcsv (من وثائق الجوهرة) كما يلي:
csv_string = FasterCSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
لقد نجح الأسلوب التالي بشكل جيد في حالتي وتسبب في قيام المتصفح بفتح التطبيق المناسب لنوع CSV بعد التنزيل.
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
جرب جوهرة جميلة لإنشاء ملف CSV من Railshttps://github.com/crafterm/comma
ألق نظرة على جوهرة CSV Shaper.
https://github.com/paulspringett/csv_shaper
إنه يحتوي على DSL رائع ويعمل بشكل جيد مع موديلات Rails.كما أنه يتعامل مع رؤوس الاستجابة ويسمح بتخصيص اسم الملف.
إذا كنت تريد ببساطة الحصول على قاعدة بيانات CSV بنفسك من وحدة التحكم، فيمكنك القيام بذلك في بضعة أسطر
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(""))}