我的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 %>
答案 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
方法返回的内容。