Deepender Singla
Deepender Singla

Reputation: 997

rescuing active record : Record Invalid

This is my code.

class Product < ActiveRecord::Base
 attr_accessible :name, :price, :released_on
begin
  validates :name, uniqueness: true
  rescue ActiveRecord::RecordInvalid => e
  render( inline: "RESCUED ActiveRecord::RecordInvalid" )
  return
end
def self.to_csv(options = {})
CSV.generate(options) do |csv|
  csv << column_names
  all.each do |product|
    csv << product.attributes.values_at(*column_names)
  end
end
end



def self.import(file)
CSV.foreach(file.path , headers:true) do |row|
Product.create! row.to_hash   # If we want to add a new item

end
end
end

when I save a duplicate model with same name an exception is raised

ActiveRecord::RecordInvalid in ProductsController#import

Validation failed: Name has already been taken

Rails.root: /home/deepender/396-importing-csv-and-excel/store-before

I am using rescue operation still it is not handling error? Any guesses where I am wrong.

Upvotes: 1

Views: 8008

Answers (2)

As Cody mentioned, do not wrap you valites in begin/rescue, because the validates method is just telling your model what need to be validated, it's not where the actual validation method is running.

Then, here's what your import method should look like :

def import(file)
  CSV.foreach(file.path , headers:true) do |row|
  product = Product.new(row.to_hash)

  if product.save
    # product valid and created 
  else
    # invalid record here... you can inspect product.errors
  end

end

Upvotes: 3

Cody Caughlan
Cody Caughlan

Reputation: 32758

Couple things. You don't wrap your validates in begin/rescue blocks. So your model should only look like:

class Product < ActiveRecord::Base
  attr_accessible :name, :price, :released_on
  validates :name, uniqueness: true
end

And its in the controller where you perform the validation and handle it appropriately. A sample controller might look like:

class ProductsController < ApplicationController
  def create
    @product = Product.new(params[:product])
    if @product.valid?
      @product.save
      flash[:notice] = "Product created!"
      redirect_to(@product) and return
    else
      render(:action => :new)
    end
  end
end

And then in your view you might render the actual errors back to the user:

# app/views/products/new.html.erb

<%= error_messages_for(@product) %>
.. rest of HTML here ..

error_messages_for is no longer included in Rails by default and its in the gem dynamic_form

For a generic method of displaying errors see this Rails Guide:

http://guides.rubyonrails.org/active_record_validations.html#displaying-validation-errors-in-views

Upvotes: 5

Related Questions