I have a test that is raising an error. To track down the problem I ended up adding this method to a model called NodeAffiliation:
def initialize a1, a2
raise "kaboom"
end
and then I get this error:
RuntimeError: kaboom
app/models/node_affiliation.rb:13:in `initialize'
test/unit/audit_test.rb:10:in `__bind_1318003437_24401'
but audit_test.rb is doing this:
Factory.create :form
Somehow, creating a Form also creates a NodeAffiliation, but those steps seem to be missing in the backtrace. Any ideas why and/or how to get them?
The test logs might already have the stacktrace, but if not you can call
logger.debug $!.backtrace.join("\n")
where $! is the default name of the exception that was raised. This needs to be in a rescue block. I would check your factory implementation, it is likely associating node_affiliation with form objects, or perhaps there is a chain of relations. Any associations declared in the factory get created when the object is created.
Related
Why is NoMethodError not differentiated for nil in Ruby?
Calling a method on nil is an extremely common error and is usually caused by incorrect data being provided to the program. A NoMethodError on any other class usually implies an error in the code itself (e.g. why were you calling reconnect on a Document? There is likely an error in the code).
What problems are created if I add the following code to my project?
NilReferenceError = Class.new(NoMethodError)
class NilClass
def method_missing(symbol, *args)
raise NilReferenceError, "undefined method `#{symbol}' for nil:NilClass", caller
end
end
I want to do this because when I am triaging exceptions, a NilReferenceError is likely to be caused by bad data and the root cause is likely in another location (validation of input, for example). By contrast, a NoMethodError is likely to be a programming error rooted exactly at the line of the exception (easier to fix and also highly likely to happen 100% of the time).
What are the negative effects of adding code like that to my project?
I think this is just habits from other programming languages. In ruby, nil is a first class object, like an integer, a hash or your own class object.
After you see the "NoMethodError: undefined method xxx for nil:NilClass" error once or twice, you get used to it.
There is nothing wrong with monkeypatching nil to show a more descriptive error message, but it's not going to solve the root cause of the problem, which is coding practice that permits and propagates nil values.
Consider the following very contrived example:
def do_something(input)
object = fetch_something_with(input[element])
do_something_with(object)
end
A couple of ways this might blow up:
input hash does not contain element, and passes nil into fetch_something_with
fetch_something_with returns nil (by design or upon failure), which gets passed into do_something_with
An alternative approach might be:
def do_something(input)
object = fetch_something_with(validated_input)
object && return do_something_with(object)
end
def validated_input(input)
input.fetch(element) # fetch raises an exception if the value is not present
end
A bit more code, but it gives us peace of mind that this code isn't going to silently pass nil down the line to fail at some later point.
Of course, it doesn't make sense to be this paranoid in every single method, but it is good practice to have well thought out boundaries in your code, either at method or object level. Having nil slip by frequently is a sign that these borders need some strengthening.
Do you mean that, when doing something like b=nil; b.say_hello;, ruby will give you "undefined method `say_hello' for nil:NilClass (NoMethodError)" instead of something like (as in your claim) "undefined method `say_hello' for nil:NilClass (NilReferenceError)"?
Ruby is not wrong for this since nil is an object like other objects. It has methods like to_s, so ruby can't ban any call by just raising an exception saying "because it is nil, you cannot do anything. I will give you a NilReferenceError".
You can surely do as your code above if you know that what you are doing may prevent ruby's default behavior.
I am new to rails and notice a very odd pattern. I thought some error messages in Django were obscenely cryptic, but building my second app in rails I notice my errors come up NoMethodError more than 90% of the time.
How do rails people tell the difference between all these errors with the same name?
What does NoMethodError mean at it's core? It seems like what you're calling in the template is misspelled, or you're accessing attributes that don't exist?
Where can this error happen? Is the only possible cause in the template/view (the html.erb file)? Or can a bad call in the controller and whatnot cause same error?
Also, what is the best debugger gem to alleviate these issues? Reading the full trace isn't too helpful for beginners at least for a while, I;d like a first hand account of what debugger someone uses instead of reading hype
Thank you kindly
NoMethodError means you are calling a method on an object, but that object doesn't provide such method.
This is a quite bad error in the sense that is reveals a poorly designed and tested application. It generally means your code is not behaving as you are expected.
The way to reduce such errors is:
Make sure that when you are writing the code you are taking care of the various edge cases that may happen, not just the correct path. In other words, you need to take care of validating what's going on and making sure that if something is not successful (e.g. the user is not supplying all the input requested) your application will handle the case gracefully.
Make sure you write automatic test cases that covers the behavior of each method in your codebase
Keep track of the errors. When an error occurs, write a test to reproduce the behavior, fix the code and check the test passes. That will reduce the risk of regression.
This is not a Rails specific error actually. I'll try to explain what's happening at its core.
Ruby is a language that functions through message passing. Objects communicate by sending messages to each other.
The message needs to be defined as a method on the object to respond to it. This can be directly defined on the object itself, the object's class, the object's class's parents/ancestors or through included modules.
class MyObject
def some_method
puts "Yay!"
end
end
> MyObject.new.some_method
Yay!
Objects can define method_missing to handle unexpected messages.
class MyObject
def method_missing(name, *args, &block)
puts name
end
end
> MyObject.new.some_undefined_method
some_undefined_method
Without the method_missing handler, the object will raise a NoMethodError
class MyObject
end
> MyObject.new.some_undefined_method
NoMethodError: undefined method 'some_undefined_method' for #<MyObject...>
So what does this look like in Rails?
$ rails generate model User name:string
Produces this
# models/user.rb
class User < ActiveRecord::Base
end
Which has the following methods implemented among others (by ActiveRecord)
def name
end
def name=(value)
end
When you do the following:
# create a new User object
> user = User.new
#<User ... >
# call the 'name=' method on the User object
> user.name = "name"
"name"
# call the 'name' method on the User object. Note that these are 2 different methods
> user.name
"name"
> user.some_undefined_method
NoMethodError: undefined method 'some_undefined_method' for #<User...>
You'll see the same results whether you're calling it in your console, your model, your controller or in the view as they're all running the same Ruby code.
ERB view templates are slightly different in that what you enter is only evaluated as Ruby code when it's between <% %> or <%= %>. Otherwise, it gets written out to the page as text.
How do rails people tell the difference between all these errors with
the same name?
We usually look at the stack trace that comes back with the response (in development mode) as well as looking in the logs. In a dev environment, I am running my server in a console where I can scroll through the request.
What does NoMethodError mean at it's core? It seems like what you're
calling in the template is misspelled, or you're accessing attributes
that don't exist?
Due to dynamic coupling nature of Ruby. When Ruby determines that an object doesn't have a method by the name of the one that was called. It looks for a method by the name of "method_missing" within that object. If it's not defined then the super one is called which has the default behaviour of raising an exception. Rails leverages this mechanism heavily in it's internal dispatching
Where can this error happen? Is the only possible cause in the
template/view (the html.erb file)? Or can a bad call in the controller
and whatnot cause same error?
This error can happen wherever you have Ruby code, It has nothing to do with rails
Also, what is the best debugger gem to alleviate these issues? Reading
the full trace isn't too helpful for beginners at least for a while,
I;d like a first hand account of what debugger someone uses instead of
reading hype
An Invaluable tool for debugging is the gem 'pry'. It has many useful plug-able tools that greatly simplify debugging
Active Record validations throw an error when they fail. What I have in a model is
validate_format_of :field_which_cannot_have_spaces, :with => /^[^\s]+$/, :message => "Some error message"
What I want instead, is for a string replacement to substitute spaces for underscores (snake_case).
The advantages of using validation for me, are that it runs every time the field is changed unless save(validate: false), and that I don't need to repeat the replacement in the create and update controller methods.
Front end javascript solutions won't help if the user hacks the form... a rails solution is needed!
It sounds like you want a callback rather than a validation. This can run each time your object is modified.
So, to remove spaces from your field before the object is saved you can do:
before_save :remove_spaces_from_x
def remove_spaces_from_x
self.field_which_cannot_have_spaces.gsub!("\s","_")
end
Note also that validation do not always raise an error when they fail. If you use save! or create! then an error is raised but if you use the equivalent save or create then no error is raised, false is returned and the object's errors are populated with details of the validation failure.
Co-worker just told me to do the following in the model:
def field_which_cannot_have_spaces=(input_from_form)
super(input_from_form.gsub("\s","_"))
end
This will change the value as it is set.
"Validations are for informing the client there is a problem, and shouldn't be doing something other than throwing an error."
Hope this helps someone else...
I have a Ruby on Rails application where a validation is failing for one of my models. There are different entry points into the code base for where this validation could fail. I'm interested in figuring out where it's coming from. Since it is a simple validation method, there aren't any exceptions involved, I just return false from the method and the save fails.
Is it currently possible to also log the backtrace to figure out what service/route this validation originated from so I can see what caused the state to change for this object in order for it to fail validation?
You could try caller():
def foo2
puts caller
end
def foo
foo2 #line5
end
foo #line 7
Result:
test.rb:5:in `foo'
test.rb:7:in `<main>'
I'm not sure of a clever way to do it, but this will get the job done. You could wrap it in a nice little function even. I'm not sure if throwing exceptions and rescuing them will impact performance, but you probably wouldn't want to do something like this in production.
begin
throw
rescue
puts $!.backtrace
end
In my Rails 3.0.11 app, we have very simple code in a controller:
def index
#record = Record.valid # scope around 80,000 records
asdfasdfsa # consider this is a typo to raise NameError Exception
end
The interesting thing is that when it came to the typo, the app seems to query/execute the #record instance variable first before raising an exception. The query costs almost 1 min to get records. So in browser, the page hanges for a long while before coming into an exception template.
If I replace #record with a local variable "record", the querying doesn't happen at all. Anyone knows what it is going on?
As #Khronos points out, it's due to the error message and evaluating the variable, but it's not to_s, it's #inspect.
in actiondispatch/middleware/templates/rescues/diagnostic.erb it calls <%=h #exception.message %> to display the error. A quick jaunt into irb provided this tidbit:
class Object ; def inspect; "foo" ; end ; end
=> nil
a=Exception.new(Object)
=> #<Exception: #<Exception:0x10d8a4108>>
a.message
=> foo
So I think #exception.message will call inspect on the exception, which in turn probably calls inspect on the controller. While it enumerates the entire object during inspect it runs the query, but when it runs to_s I think it drops all that for just the object id.
I'm still a bit fuzzy, but it does at least have to do with the exception and inspect.
See my blog post Ruby's Inspect Considered Harmful for details about this very issue. In short, though:
NameError calls inspect when formatting its error message
The default implementation of inspect calls inspect on all instance variables recursively
NameError throws away the result of inspect if it is longer than 65 characters
For us, this meant that a typo in a View caused Rails to hang for 20 minutes while Ruby built a huge, 20MB string and then proceeded to throw it away
It took us 7 months to get a trivial fix for this into Rails core
In short, I consider the behaviour of NameError to be a heinous bug within the Ruby interpreter. I can think of no sane reason for this implementation.
This is a side effect of the exception handling code.
Think of the behavior you're seeing in your two cases.
Instance Variable -
You've assigned the query to an instance variable of the controller. You then throw an exception and as part of that exception handling rails will call to_s on the controller, which then forces the query to execute as by default it shows all the instance variables.
Local Variable -
You've assigned the query to a local variable of the controller. When the exception is thrown in this case the local variable is just thrown away.
I find it good practice to always override to_s on objects where creating string representations of the structure could be expensive and/or spammy in the ruby console.