Recording errors

I am using restful_authentication in a rails app, but I also wanted to
let administrators create news users by piggybacking on the
restful_authentication function.

I decided to allow csv imports for creating members in a two step
process similar to this one, http://goodbadtech.com/2009/05/13/ruby-on-rails-import-csv-data-into-database/

So I import the csv using PaperClip and then process it to create
users etc. I also use a rescue in case exceptions are thrown, but I
would like to record these errors for display after the entire csv has
been imported. I thought about creating a new model, ImportError that
belonged to import, so that each csv file could have a list of error
messages later on.

But I can't get the recording part to work. Users are created and
stored, but the rescue action overrides everything else when errors
like duplicate entries come up.

here is my controller.

class ImportsController < ApplicationController
  before_filter :check_administrator_role #protect controller from
anonymous users

  def new
    @import = Import.new
  end

  def create
    @import = Import.new(params[:import])

    respond_to do |format|
      if @import.save!
        flash[:notice] = 'CSV data was successfully imported.'
        format.html { redirect_to(@import) }
      else
        flash[:error] = 'CSV data import failed.'
        format.html { render :action => "new" }
      end
    end
  end

  def show
    @import = Import.find(params[:id])
  end

  def proc_csv
    @import = Import.find(params[:id])
    lines = parse_csv_file(@import.csv.path)
    #lines.shift #comment this line out if your CSV file doesn't
contain a header row
    if lines.size > 0
      @import.processed = lines.size
      lines.each do |line|
          new_user(line)
      end
      @import.save
      flash[:notice] = "CSV data processing was successful."
      redirect_to :action => "show", :id => @import.id
    else
      flash[:error] = "CSV data processing failed."
      render :action => "show", :id => @import.id
    end
  end

private

  def parse_csv_file(path_to_csv)
    lines = []

    #if not installed run, sudo gem install fastercsv
    #http://fastercsv.rubyforge.org/
    require 'fastercsv'

    FasterCSV.foreach(path_to_csv) do |row|
      lines << row
    end
    lines
  end

  def new_user(line)
          params = Hash.new
          params[:user] = Hash.new
          params[:user]["name"] = line[0]
          params[:user]["email"] = line[1]
          params[:user]["password"] = random_password
          params[:user]["password_confirmation"] = params[:user]
["password"]
          @user = User.new(params[:user])
          member_role = Role.find_by_rolename('member')

          if @user.save!
          @user.roles << member_role
            else
          record_error(line)
           end

      rescue ActiveRecord::RecordInvalid
  end

  def random_password(size = 8)
    chars = (('a'..'z').to_a + ('0'..'9').to_a) - %w(i o 0 1 l 0)
    (1..size).collect{|a| chars[rand(chars.size)] }.join
  end

  def record_error(line)
          params = Hash.new
          params[:import_error] = Hash.new
          params[:import_error]["import_id"] = @import.id
          params[:import_error]["name"] = line[0]
          params[:import_error]["email"] = line[1]
          params[:import_error]["error_message"] = flash[:error]
          @import_error = User.new(params[:import_error])
          @import_error.save!
  end

end

This else statement will never execute since if save! fails it raises
an exception. Did you want to use save instead ?

Fred

Hi Fred,

You are right about the conditional statement being rubbish.

What I really want is to save users that pass the validations and any
lines in the csv that fail to get skipped over, but remember the error
that was generated.

Without rescue the whole action would fail.

I am just not sure how to record those errors and associate them with
this particular import.

Dan

Hi Fred,

You are right about the conditional statement being rubbish.

What I really want is to save users that pass the validations and any
lines in the csv that fail to get skipped over, but remember the error
that was generated.

Well if you use save rather than save! it won't raise an exception if
the record is invalid. If you want the individual errors they'll be in
your_object.errors.

Fred