Rails FastCSV导入功能

时间:2012-06-10 17:58:03

标签: ruby-on-rails

我的Rails应用程序中的当前Model代码使用“text”作为键,然后根据天气重复或不更新或创建新行。我正在寻找一个替换代码,它应该将所有行导入数据库(因此不需要使用文本作为键,接受dublicate内容)。谁知道怎么做?

的routes.rb

MyApp::Application.routes.draw do

resources :users do
member do
  get :following, :followers
end
end
resources :sessions,        only: [:new, :create, :destroy]
resources :microposts,      only: [:create, :destroy]
resources :relationships,   only: [:create, :destroy]
resources :password_resets
resources :banklines,       only: [:create, :destroy]
resources :booklines,       only: [:create, :destroy]

root to: 'static_pages#app'

post  '/upload_booklines',  to: 'booklines#upload_booklines'
match '/board',             to: 'static_pages#home'
match '/signup',            to: 'users#new'
match '/signin',            to: 'sessions#new'
match '/signout',           to: 'sessions#destroy', via: :delete
match '/help',              to: 'static_pages#help'
match '/about',             to: 'static_pages#about'
match '/contact',           to: 'static_pages#contact'

控制器/ booklines_controller.rb

class BooklinesController < ApplicationController

require 'csv'

def upload_booklines
 if request.post? && params[:file].present?
  infile = params[:file].read
  n, errs = 0, []

  CSV.parse(infile) do |row|
    n += 1
    next if n == 1 or row.join.blank?
    @bookline = current_user.booklines.build_from_csv(row)
    if @bookline.valid?
      @bookline.save
    else
      errs << row
    end
  end
  redirect_to root_path
  end
end

模型/ bookline.rb

class Bookline < ActiveRecord::Base
attr_accessible :amount, :appendix_number, :date, :text

belongs_to :user, dependent: :destroy

    scope :active, where(:active => true)
    scope :latest, order('created_at desc')

  def self.build_from_csv(row)
    bookline = find_or_initialize_by_text(row[1])
    bookline.attributes ={:date => row[0], :amount => row[2], :appendix_number => row[3]}
  return bookline
  end
end

查看/ static_pages / app.html.erb

<%= form_tag('upload_booklines', :multipart => true) do %>
  <p>
     File:<br />
     <%= file_field_tag 'file' %><br />
   </p>
 <p>
   <%= submit_tag "Upload" %>
 </p>
<% end %>

1 个答案:

答案 0 :(得分:1)

首先,由于您只回复了来自POST的{​​{1}}(通常情况只响应一个动词),您可以将路线修改为看起来像这样:

booklines#upload_booklines

然后,如果请求是post '/upload_booklines', to: 'booklines#upload_booklines',则可以删除条件检查。

现在,就你的问题而言,这就是我要做的事情:

POST

第一种方法# models/bookline.rb def self.create_from_csv(row) create do |b| b.date = row[0] b.text = row[1] b.amount = row[2] b.appendix_number = row[3] end end # controllers/bookslines_controller.rb def upload_booklines redirect_to root_path, notice => "You must upload a .CSV file to parse." unless params[:file].present? CSV.parse(params[:file]) do |row| @bookline = current_user.booklines.create_from_csv(row) end end 进入模型。它将从控制器传入的CSV行创建新记录。第二种方法create_from_csv进入控制器。它只是打开文件并将每一行读入upload_booklines方法。

我在create_from_csv中明确设置了属性,因为我不确定行中的所有数据是否都进入模型。如果你也不确定,你应该使用这个实现。但是,如果所有数据映射到所有属性,则DRYer和类似Ruby的方式如下:

create_from_csv

基本上,我们将行对象从CSV解析器转换为哈希,哈希可以直接传递给create方法。这与标准# models/bookline.rb # Only use this if all of the data in the CSV row maps to attributes in the model def self.create_from_csv(row) create(row.to_hash) end 控制器方法的工作方式非常相似; create变量由Rails从请求映射到散列。

另外,作为旁注,您不需要明确地返回Ruby。方法中的最后一个语句将自动返回。在原始params方法中,您可以简单地编写build_from_csv,而不使用booklines关键字。在我的return方法中,将返回新创建的create_from_csv记录,因为这是Bookline方法返回的内容。