1. 程式人生 > >Ruby中,ActiveRecord 初次使用心得(一)

Ruby中,ActiveRecord 初次使用心得(一)

自己要寫一個將csv檔案資料匯入資料庫的Ruby程式,用到了ActiveRecord,程式如下:

require 'csv'
require 'rubygems'
require 'active_record'
require 'yaml'

class_name = ARGV[0].split('/').last.split('.')[0]

eval("
        class #{class_name} < ActiveRecord::Base
        end
     ")                                                   #Create class dynamicly

class Import_csv_data

  def initialize(csv_file_path)    #Method initialization gets csv_file_path form command line   
    if csv_file_path.eql?(nil)
      puts 'Please ruby the file with csv file path, such as "ruby example.rb /home/..example.csv"'
    else     
        @table_name = csv_file_path.split('/').last.split('.')[0]
        @csv_file_path = csv_file_path
        @field_num = 0
    end
  end
 
  def import_data()    #Main Method. invoke Method read_csv_file, connect_db
    if @table_name
      connect_db()
      all_data = read_csv_file()
      1.upto(all_data.length - 1) do |data_index|
        data = []
        sql = make_sql(all_data, data_index)
        puts sql
        eval("
              data = #{@table_name}.find_by_sql \"#{sql}\"
             ")
                                        
        if data.eql?([])                                      
          Object::const_get(@table_name).new do |value|
            0.upto(all_data[0].length - 2) do |num|
              eval("
              value.#{all_data[0][num]} = #{all_data[data_index][num]}
                   ")                                       
            end
            value.save                                         
          end
        end
      end
    end
  end
 
  private
  def read_csv_file()    #Method read_csv_file is to get data from csv file, return all_data which
                         #is two-dimensional array.
    all_data = []
    CSV.open(@csv_file_path,'r') do |row|
      all_data << row
      @field_num = row.length - 1
    end
    return all_data
  end
 
  def connect_db()    #Method is to connect DB
    db_config = YAML.load(File.open("db_config.yaml"))    #Get congfigrat
    ActiveRecord::Base.establish_connection(:adapter  => db_config["adapter"],
                                            :host     => db_config["host"],
                                            :username => db_config["username"],
                                            :password => db_config["password"],
                                            :database => db_config["database"])
    ActiveRecord::Base.pluralize_table_names = false
  end

  def make_sql(all_data, data_index)  #Method is to make sql query
    table_name = @table_name.downcase
    sql = "select * from #{table_name} where "
    1.upto(ARGV.length - 1) do |argv_index|
      unless argv_index == 1
        sql << " and "
      end
        sql << "#{all_data[0][ARGV[argv_index].to_i]} = #{all_data[data_index][ARGV[argv_index].to_i]}"
    end
    return sql
  end

end

Import_csv_data.new(ARGV[0]).import_data()

功能不算複雜,編寫的過程卻異常艱難:

  1,因為要做到通用性,根據csv檔案的名字將資料匯入相應的表中,所以繼承於ActiveRecord::Base的類要動態生成,這裡,我用了最簡單的方法:eval(“ your codes ”),其實,還有很多其他的方法,例如,Object::const_set(@table_name),等等。

  2,在用到ActiveRecord包時,遇到複合主鍵的問題,因為ActiveRecord不支援複合主鍵,所以我自己編寫了SQL語句,但是在呼叫方法#{@table_name}.find_by_sql 時,總是報語法錯誤,反覆除錯後,發現在SQL語句兩邊加雙引號 \"#{sql}\" 後,問題解決。