2016年3月27日 星期日

[rails]HOW TO: 將txt格式資料匯入資料庫的頁面

參 考https://richonrails.com/articles/importing-csv-files index.html.erb

說明:
我們想要在records底下新建一個頁面([project path]/records/import/),在這個頁面使用者可以選擇想要上傳的local端檔案,然後按下import按鈕匯入資料。

首先是要處理當使用者輸入網址/import/時,由show action 處理,並 render import.html.erb
app/controller/records_controller.rb
  def show
    if valid_page?
      render params[:id]
    else
      render file:"public/404.html", status: :not_found
    end
  end
         

在指定的頁面 (在這裡是import.html.erb)中加入可以上傳檔案的html
<h1>import csv file</h1>
    <%= form_tag import_records_path, multipart: true do %>
      <%= file_field_tag :file %>
      <%= submit_tag "Import CSV" %>
    <% end %>
 

目前為止rails 還不知道import_records_path會回傳什麼path,所以需要在config/routes中定義:
resources :records do
      collection{post:import}
end

接下來當在index.html.erb頁面,使用者選擇本機端的特定檔案後,按下Import CSV 按扭,router會導引到records/import/ 這個path(並將特定 檔案的path存到變數:file),而當rails接收到records/import這個path ,會去執行records controller底下的#import action。

於是我們要定義import action. edit app/controller/record_controller.rb

def import
      Record.import(params[:file])
 end

我們希望使用import這個method來將資料匯入,目前為止還沒有定義這個method,而這個method是Record Object底下的方法,所以我們接下來要定義他
app/models/record.rb
  require 'csv'
  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|

      record_hash = row.to_hash #把csv檔的以列(row)為單位pop-out
      record = Record.where(id: record_hash["id"])

      if record.count == 1
        record.first.update_attributes(record_hash)
      else
        Record.create!(record_hash)
      end # end if !record.nil?
    end # end CSV.foreach
  end # end self.import(file)

這段程式會把csv檔的第一行作為index,存到record_hash這個變數中,找到指定的欄位
當原始資料庫中沒有值時,會初始之,若已經有資料了,就加上去。

example.csv
program_id,distance,property_id,minutes,seconds,user_id,owner_id,month,date,year
1,1,1,2,2,1,1,3,22,2016
1,1,1,2,2,1,1,3,22,2015
1,1,1,2,2,1,1,3,22,2014

圖一:加入上傳資料功能後的頁面 


圖二:選擇檔案後,會在頁面上顯示路徑

圖三:資料成功加入資料庫


延伸應用:可應用於使用者上傳檔案,運算後輸出