0

我的 Rails 应用程序中的当前模型代码使用“文本”作为键,然后根据天气更新或创建新行,它是否重复。我正在寻找应将所有行导入数据库的替换代码(因此无需使用文本作为键,可以接受重复的内容)。有谁知道如何做到这一点?

路线.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 %>
4

1 回答 1

1

首先,由于你只响应POSTfrom 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

第一种方法,create_from_csv进入模型。它将从控制器传入的 CSV 行创建一个新记录。第二种方法upload_booklines进入控制器。它所做的只是打开文件并将每一行读入create_from_csv方法中。

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

# 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

本质上,我们将行对象从 CSV 解析器转换为哈希,可以直接传递给 create 方法。create这与标准控制器方法的工作方式非常相似;Rails将params变量从请求映射到散列。

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

于 2012-06-10T19:06:30.353 回答