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'

controllers/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

models/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(通常、アクション1 つの動詞にのみ応答する必要があります)、次のようにルートを変更できます。

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 行から新しいレコードを作成します。2 番目のメソッド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これは、標準のコントローラー メソッドが機能する方法と非常によく似ています。このparams変数は、Rails によってリクエストからハッシュにマップされます。

また、補足として、Ruby で明示的に返す必要はありません。メソッドの最後のステートメントが自動的に返されます。元のメソッドでは、キーワードなしでbuild_from_csv単純に記述できました。私のメソッドでは、メソッドが返すものとして、新しく作成されたレコードが返されます。booklinesreturncreate_from_csvBooklinecreate

于 2012-06-10T19:06:30.353 に答える