I am developing a RoR application. I need to use a custom exception I implemented. It looks like this:
# app/exceptions/JobError.rb
module Exceptions
class JobError < StandardError
# ...
end
end
However, I got a uninitialized constant JobError when I raise the exception. I tried different namespaces but none of them work:
raise JobError.new()
raise Exceptions::JobError.new()
raise ::Exceptions::JobError.new()
Any idea?
My bad, I wrote the file name in CamelCase, not in snake_case...
Related
My application has lib/project/errors which contains a bunch of Exception classes, one of which is ServiceException
module Project
module Errors
class ServiceException < Exception
def initialize(message = nil)
super message
end
end
end
end
I am trying to use this in my GameService:
module GameMan
class GameService
Blah blah
def validate(score)
raise Project::Errors::ServiceException.new('blah')
end
end
end
This works,
however I hate writing the full module path everywhere. Is there a way to avoid this?
I have tried
module GameMan
class GameService
include Project::Errors
Blah blah
def validate(score)
raise ServiceException.new('blah')
end
end
end
This gives
uninitialized constant ServiceException error.
I have
config.autoload_paths +=
%W(#{config.root}/lib #{config.root}/app/services)
already set inapplication.rb``
What am I doing wrong?
It is all about constants lookup.
ServiceException is defined in the scope of Project::Errors. When you reference ServiceException without prefixing Project::Errors it looks for the class defined in the outer scope, and failing, because there is none.
You should be using the full path.
include Project::Errors
Replace above line to following line
include Project::Errors::ServiceException
I don't understand well how Rails include (or not?) some file from the app directory.
For example, I've created a new directory app/exceptions for create my own exceptions. Now, from a helpers file, I want to raise one of my exception.
Am I suppose to include something in this helper?
The Helper: helpers/communications_helper.rb
//should I include something or it's suppose to be autoloaded?
module CommunicationsHelper
begin.
.
.
.
raise ParamsException, "My exception is lauch!"
rescue StandardError => e
...
end
end
The exception: exceptions/params_exception.rb
class ParamsException < StandardError
def initialize(object, operation)
puts "Dans paramsException"
end
end
Nothing specific from my raise in the output...
Thanks!
EDIT:
Thanks to all, your two answers was helpful in different way.
I didn't raise well the exception like you said, but I've also forggot to update my config.rb.
so now I 've:
rescue StandardError => e
raise ParamsError.new("truc", "truc")
Other question, do you know where can I catch the raise?
Cause I'm already in a catch block, so I'm little lost...
If you don't see output from your raise, make sure you're not rescuing the error by accident, since your error is a subclass of StandardError:
begin
raise ParamsException, "My exception is lauch!"
rescue StandardError => e # This also rescues ParamsException
end
As a side note, in Ruby it's common practice to have your custom errors end with Error rather than Exception. Unlike some other programming languages, classes ending with Exception are meant for system level errors.
First, I think that you're raising your exception incorrectly.
In your custom exception class, your initialize method takes in arguments. Therefore you should raise it with:
raise CustomError.new(arg1, arg2, etc.)
Read this.
Lastly, don't rescue from StandardError if CustomError is a child of StandardError; otherwise your manual 'raise' will be rescued.
I have this piece of code that I am trying to test:
def error_from_exception(ex)
if ex.is_a?(ActiveRecord::RecordInvalid)
...
To get into the if block, I need to pass in the correct ex param.
How do I create an ActiveRecord::RecordInvalid?
With rspec, I'm trying to do something like this:
context 'exception is ActiveRecord::RecordInvalid' do
it 'returns the validation error' do
begin
raise ActiveRecord::RecordInvalid
rescue Exception => ex
binding.pry
###
# From my pry session:
# $ ex
# $ <ArgumentError: wrong number of arguments (0 for 1)>
# $ ex.class
# $ ArgumentError < StandardError
###
end
end
end
How do I find out what argument type the library is looking for?
RecordInvalid link
None of the above methods worked for me so I finally did the following while doing a spec:
class InvalidRecord
include ActiveModel::Model
end
raise ActiveRecord::RecordInvalid.new(InvalidRecord.new)
Hope it helps!
EDIT: This is now possible in Rails 5.1.1. The record argument is no longer required after this commit: https://github.com/rails/rails/commit/4ff626cac901b41f86646dab1939d2a95b2d26bd
If you are on a Rails version under 5.1.1, see the original answer below:
It doesn't seem like it is possible to raise an ActiveRecord::RecordInvalid by itself. If you look at the source code for ActiveRecord::RecordInvalid, it requires a record when initializing:
class RecordInvalid < ActiveRecordError
attr_reader :record # :nodoc:
def initialize(record) # :nodoc:
#record = record
...
end
end
(source: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/validations.rb)
Something you could do to work around this would be to simply create an actual record that is invalid and attempt to save it using save! (such as calling User.new.save! when User.name is required). However, keep in mind that this might potentially become a problem in the future if the model you use is changed and it becomes valid inside your test (User.name is no longer required).
I needed to do something similar to test my code's handling of ActiveRecord::RecordInvalid. I wanted to do
allow(mock_ar_object).to receive(:save!).and_raise(ActiveRecord::RecordInvalid)
but that gives ArgumentError: wrong number of arguments (0 for 1) when RSpec tries to instantiate RecordInvalid.
Instead I wrote a RecordInvalid subclass and overrode initialize like this:
class MockRecordInvalid < ActiveRecord::RecordInvalid
def initialize
end
end
allow(mock_ar_object).to receive(:save!).and_raise(MockRecordInvalid)
Then a rescue ActiveRecord::RecordInvalid will catch MockRecordInvalid and MockRecordInvalid.new.is_a?(ActiveRecord::RecordInvalid) is true.
ActiveRecord::RecordInvalid needs an object to be created.
If you want to test just the exception itself, try:
null_object = double.as_null_object
ActiveRecord::RecordInvalid.new(null_object)
Understand the double as null object here (https://www.relishapp.com/rspec/rspec-mocks/v/2-6/docs/method-stubs/as-null-object)
I am using update_attribute(attr, 'value') instead of save! and I can mock the update_attribute method as follows:
expect(mock_object).to receive(:update_attribute).with(attr, 'value').and_raise(ActiveRecord::RecordInvalid)
We can stub it to the Model like this,
ModelName.any_instance.stubs(<method_name>).raises(ActiveRecord::RecordInvalid.new(record))
Example:
Post.any_instance.stubs(:save!).raises(ActiveRecord::RecordInvalid.new(post))
I'm following instructions at http://ariejan.net/2011/10/14/rails-3-customized-exception-handling/ and have hit a road block.
I am relatively new to rails, so I'm not sure what I've done right/not-so-right.
The first step was to create class
MyApp::ProfileNotFoundError < StandardError
end
So I went to app/models and created profile_not_found.rb which contains the following, where (APP) is the name of my app as defined by Rails.application.class.parent_name, but I have hidden from this post for security/privacy.
(APP)::ProfileNotFoundError < StandardError
end
In app/controllers/application_controller.rb I added
rescue_from (APP)::ProfileNotFoundError, :with => :profile_not_found
and in my login controller I added
raise (APP)::ProfileNotFoundError if #profile.nil?
However, when I try to test the code, I get a Routing Error stating
uninitialized constant (APP)::BlankUsernameError
In my opinion, this suggests that I did something wrong pertaining to the class creation, but the tutorial is so vague I can't figure it out. Any pointers?
I'm running Rails 3.0.20 & Ruby 1.8.7 on Ubuntu 12.04.2 x86_64
Do you have the class keyword in your class definition?
class MyApp::ProfileNotFoundError < StandardError
end
Secondly, you'll have to require your exceptions where you're using it. This is probably the problem you're encountering with the uninitialized constant error. To do this you will probably have to wrap it in a module:
module Exceptions
class MyApp::ProfileNotFoundError < StandardError
end
end
Also, you should put your error classes in a different directory than /models. This directory should be explicitly for your models. Maybe make one like /errors.
I'm struggling to use Delayed_job (collective idea v2.0 in a Rails 2.3.8 app).
I'm calling the job from an application_controller method:
...
Delayed::Job.enqueue(S3MoverJob.new(docs))
Where docs is a Hash with ids and names of files.
At my Lib directory I have the class S3MoverJob:
class S3MoverJob < Struct.new(:docs)
def perform
#setup connection to Amazon
...
#connect
...
#loop to move files not transfered already
docs.each do |id,file_name|
# Move file
begin
doc = Document.find(id)
... perform actions
rescue Exception => exc
raise "failed!"
end
end
end
end
The problem is that it's raising: S3MoverJob failed with NoMethodError: You have a nil object when you didn't expect it!
I looked into the handler, in the DB, and it was delivering to the perform method the Yaml file with the list of ids and file names, like this:
docs:
3456: name_of_file_01.png
4567: name_of_file_02.txt
What am I missing? Thanks for helping me.
I think you should puts more information for debug.
Such as: add statements like 'Rails.logger.info "some stuff"' under the perform method to see where the exception been throw
My fault. I didn't know it was an idenpendent process and needed some requirements:
require 'yaml'
require 'uri'
class Document < ActiveRecord::Base
end
After that, everything works fine.
Thanks anyway.