Forum: RSpec Question on SQL exceptions

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-09 20:36
To prevent duplicate values in the DBMS I use a unique index on those
columns.  I am testing that duplicate values cannot, in fact, be added.

This is the cucumber scenario:

  Scenario: The legal name must be unique
    Given I do have a user named "admin"
      And the user named "admin" is authenticated
      And the user named "admin" is authorized to "add" "entities"
      And I do have an entity named "Myuser"
      And the entity named "Myuser" has a legal name "Myuser Legal Name"
    When they visit the add a new entity page
      And they enter valid entity data
      And they enter the entity legal name "MyUser  LEGAL  NAME"
      And I press "Create"
    Then they should see a save error message

This is the step definition that should be triggered:

When /should see a save error message/ do
  response.body.should =~ /errors? prohibited this (.*) from being
saved/im
end

But what happens is that SQLite3 throws an SQL exception:
  SQLite3::SQLException: column entity_legal_name is not unique:...;

that is not caught by this controller:

  def create
    @entity = Entity.new(params[:entity])

    # need this to strip out observer attributes for datebalks plugin
    # see config/initializers/hash_addins.rb

    @client = @entity.build_client(params[:client].datebalk!)

    respond_to do |format|
      if @entity.save
        flash[:notice] = 'Client was successfully created.'
        format.html { redirect_to(@client) }
        format.xml  { render :xml => @client,
          :status => :created, :location => @client }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @client.errors,
          :status => :unprocessable_entity }
      end
    end

I thought, probably incorrectly, that when #save is called then any
errors are returned to the controller to handle.  This is evidently not
happening so can someone tell me how this is supposed to be handled?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-09 21:00
James Byrne wrote:

Q.
> To prevent duplicate values in the DBMS I use a unique index on those
> columns.  I am testing that duplicate values cannot, in fact, be added.

> I thought, probably incorrectly, that when #save is called then any
> errors are returned to the controller to handle.  This is evidently not
> happening so can someone tell me how this is supposed to be handled?

A. rescue ActiveRecord::StatementInvalid
39100495c9937c39b2e0c704444e1b4a?d=identicon&s=25 Pat Maddox (Guest)
on 2009-03-09 21:19
(Received via mailing list)
ActiveRecord doesn't know anything about db constraint errors.  If one
is violated, the error propagates up in the form of an exception.

Put a validates_uniqueness_of :login_name on your User class, and
you'll get the behavior you want.  You can keep the db constraint in
as a safety net against possible race conditions at the app layer.

Pat
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-09 21:53
Pat Maddox wrote:
> ActiveRecord doesn't know anything about db constraint errors.  If one
> is violated, the error propagates up in the form of an exception.
>

I realize that, but the exception is of the
ActiveRecord:StatementInvalid class, which I should be able to catch in
the controller with a rescue clause.  But, I am not getting this to work
at the moment.  I thought that this should at least produce some out put
but it never does:


  def create
    @entity = Entity.new(params[:entity])
    ...
    respond_to do |format|
      ...
      end
    end
  rescue => my_exception
    puts "Rescue clause invoked!"
    puts my_exception
  end


For now, all I want is to see the rescue clause invoked, but it is not.
have I put this clause in the wrong place? Am I specifying it wrong?
369b9fd2a0d9e7cdbc60907a2a056ad9?d=identicon&s=25 Scott Taylor (Guest)
on 2009-03-09 22:01
(Received via mailing list)
On Mar 9, 2009, at 4:53 PM, James Byrne wrote:

> work
>      end
>    end
>  rescue => my_exception
>    puts "Rescue clause invoked!"
>    puts my_exception
>  end
>
>
> For now, all I want is to see the rescue clause invoked, but it is
> not.
> have I put this clause in the wrong place? Am I specifying it wrong?

You can try "rescue Exception" which rescues from all exceptions, not
just ones which inherit from StandardError.  (rescue without an
explicit error class *only* rescues from StandardExceptions and error
classes which derive from it):

http://gist.github.com/76474

Also - I believe this only works in 1.8.6 and above, so if you're
still on 1.8.5 I'd recommend an upgrade.

Scott
D1b0fee9c743f544f9efa49dde7965a8?d=identicon&s=25 Tim Glen (Guest)
on 2009-03-09 22:58
(Received via mailing list)
> at the moment.  I thought that this should at least produce some out
>    end
>  rescue => my_exception
>    puts "Rescue clause invoked!"
>    puts my_exception
>  end
>
>
> For now, all I want is to see the rescue clause invoked, but it is
> not.
> have I put this clause in the wrong place? Am I specifying it wrong?

Just a stab in the dark, but I haven't seen any mention of calling
save vs. save!. save just puts any errors in the model, save! will
raise the exception if there are any errors. That may not be the case
for ActiveRecord:StatementInvalid exception, but I thought i'd mention
it anyway.

timg
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-10 00:31
Tim Glen wrote:

> Just a stab in the dark, but I haven't seen any mention of calling
> save vs. save!. save just puts any errors in the model, save! will
> raise the exception if there are any errors. That may not be the case
> for ActiveRecord:StatementInvalid exception, but I thought i'd mention
> it anyway.
>
> timg

I wondered about this but I think that since the DBMS exception is not
being trapped at all that it makes no difference. However, I will check
if if it does or not anyway.

and

Scott Taylor wrote:

> You can try "rescue Exception" which rescues from all exceptions, not
> just ones which inherit from StandardError.

  Tried that one and it did not work either.

> Also - I believe this only works in 1.8.6 and above, so if you're
> still on 1.8.5 I'd recommend an upgrade.

This may be the case.  The target host runs CentOS-5.3 which ships with
Ruby-1.8.5.  I will see if I get different results on a 1.8.6 machine.
D1b0fee9c743f544f9efa49dde7965a8?d=identicon&s=25 Tim Glen (Guest)
on 2009-03-10 03:02
(Received via mailing list)
>> Just a stab in the dark, but I haven't seen any mention of calling
>> save vs. save!. save just puts any errors in the model, save! will
>> raise the exception if there are any errors. That may not be the case
>> for ActiveRecord:StatementInvalid exception, but I thought i'd
>> mention
>> it anyway.

> I wondered about this but I think that since the DBMS exception is not
> being trapped at all that it makes no difference. However, I will
> check
> if if it does or not anyway.

Right - this is from the validates_uniqueness_of documentation:
#   When the database catches such a duplicate insertion,
#   ActiveRecord::Base#save will raise an ActiveRecord::StatementInvalid
#   exception. You can either choose to let this error propagate (which
#   will result in the default Rails exception page being shown), or you
#   can catch it and restart the transaction (e.g. by telling the user
#   that the title already exists, and asking him to re-enter the
title).
#   This technique is also known as optimistic concurrency control:
#   http://en.wikipedia.org/wiki/Optimistic_concurrency_control

so it _should_ be bubbling through. Odd that it would change in Ruby
1.8.6, but it's worth a try.

timg
39100495c9937c39b2e0c704444e1b4a?d=identicon&s=25 Pat Maddox (Guest)
on 2009-03-10 03:49
(Received via mailing list)
On Mar 9, 2009, at 1:53 PM, James Byrne wrote:

> work
> at the moment.

Not sure what your problem is.  Here's a gist that demonstrates what
you're trying to do, and works fine.  http://gist.github.com/76667

Pat
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-10 14:20
Pat Maddox wrote:

>
> Not sure what your problem is.  Here's a gist that demonstrates what
> you're trying to do, and works fine.  http://gist.github.com/76667
>
> Pat

I do not know what I am doing wrong either.  I tried much the same thing
as you suggest last night in the console:

>> def my_exception(x=false)
>>   raise ActiveRecord::StatementInvalid if x
>>   puts "No Exception"
>> rescue ActiveRecord::StatementInvalid
>>   puts "exception rescued"
>> end
=> nil
>> my_exception(false)
No Exception
=> nil
>> my_exception(true)
exception rescued
=> nil

So, my version of Ruby has nothing to do with whatever is happening.  I
will poke at things some more and see if I can discover what my
misunderstanding is.  It has to be something simple that I just do not
see at the moment.
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-03-10 14:32
James Byrne wrote:

>
> I do not know what I am doing wrong either.  I tried much the same thing
> as you suggest last night in the console:

Well, whatever I was doing wrong I seem to have fixed it.  Things now
seem to be working as I intended.
This topic is locked and can not be replied to.