Ask Again Later Undefined Method for Nil nilclass

To give back to our community of developers, we looked at our database of thousands of projects and plant the superlative x errors in Red on Rails projects. We're going to prove you what causes them and how to prevent them from happening. If you lot avoid these "gotchas," it'll make yous a meliorate programmer.

Because data is king, we nerveless, analyzed, and ranked the elevation 10 Ruby errors from Ruby on Rails applications. Rollbar collects all the errors for each project and summarizes how many times each one occurred. We do this by grouping errors co-ordinate to fingerprinting. Basically, we group two errors if the 2nd ane is just a echo of the kickoff. This gives users a dainty overview instead of an overwhelmingly big dump like y'all'd run into in a log file.

We focused on the errors near probable to impact you and your users. To do this, we ranked errors by the number of projects experiencing them across different companies. We intentionally looked at the number of projects so that high-volume customers wouldn't overwhelm the information set up with errors that are non relevant to nigh readers.

Here are the meridian 10 Rail errors:

Screenshot of Rails Error Statistics

You've probably noticed some familiar faces in there already. Permit's dig in and take a look at the errors in a bit more detail to meet what might cause them in your production awarding.

We'll provide example solutions based on Runway 5, merely if yous're still using Track 4 they should point you in the right direction.

ane. ActionController::RoutingError

We start with a classic of any web application, the Rails version of the 404 fault. An ActionController::RoutingError means that a user has requested a URL that doesn't exist within your application. Rails will log this and it will look similar an error, but for the most office it is not the fault of your application.

It may be acquired by incorrect links pointing at or from within your application. It may also be a malicious user or bot testing your application for common weaknesses. If that'due south the case, you lot might observe something like this in your logs:

          ActionController::RoutingError (No route matches [GET] "/wp-admin"):        

There is one mutual reason you lot might get an ActionController::RoutingError that is caused by your awarding and not by errant users: if y'all deploy your awarding to Heroku, or any platform that doesn't permit you lot to serve static files, then you lot might find that your CSS and JavaScript doesn't load. If this is the instance, the errors will look like this:

          ActionController::RoutingError (No route matches [GET] "/assets/awarding-eff78fd93759795a7be3aa21209b0bd2.css"):        

To fix this and allow Rails to serve static assets you need to add a line to your application's config/environments/production.rb file:

          Rails.application.configure do   # other config   config.public_file_server.enabled = truthful stop        

If you aren't interested in logging 404 errors caused by ActionController::RoutingError and then you lot can avoid them by setting a catch all route and serving the 404 yourself. This method is suggested past the lograge projection{:target="_blank"}. To do so, add the following at the bottom of your config/routes.rb file:

          Runway.awarding.routes.draw practise   # all your other routes   match '*unmatched', to: 'application#route_not_found', via: :all end        

Then add the route_not_found method to your ApplicationController:

          class ApplicationController < ActionController::Base   protect_from_forgery with: :exception   def route_not_found     return file: Rail.public_path.join('404.html'), condition: :not_found, layout: false   cease end        

Before implementing this, you should consider whether knowing nearly 404 errors is important to y'all. You should also keep in mind that whatever route or engine that is mounted after the awarding loads won't be reachable{:target="_blank"} as they will be defenseless past the catch all route.

two. NoMethodError: undefined method '[]' for aught:NilClass

This ways that you lot are using square bracket notation to read a property from an object, but the object is missing, or cipher, and thus it does not support this method. Since nosotros are working with square brackets, information technology'due south likely that nosotros're digging through hashes or arrays to access properties and something along the style was missing. This could happen when you're parsing and extracting information from a JSON API or a CSV file, or just getting data from nested parameters in a controller action.

Consider a user submitting address details through a form. You lot might look your parameters to look like this:

          { user: { address: { street: '123 Simulated Street', town: 'Faketon', postcode: '12345' } } }        

You might then admission the street past calling params[:user][:accost][:street]. If no address was passed and then params[:user][:address] would exist nada and calling for [:street] would raise a NoMethodError.

You could perform a nil check on each parameter and return early using the && operator, similar so:

          street = params[:user] && params[:user][:address] && params[:user][:accost][:street]        

While that will practice the job, thankfully at that place is now a better way to access nested elements in hashes, arrays and result objects similar ActionController::Parameters. Since Cherry-red 2.3, hashes, arrays and ActionController::Parameters have the dig method{:target="_blank"}. dig allows you to provide a path to the object you want to retrieve. If at any stage nil is returned, and so dig returns nix without throwing a NoMethodError. To get the street from the parameters in a higher place you tin can phone call:

          street = params.dig(:user, :accost, :street)        

You won't get whatsoever errors from this, though you practice need to exist enlightened that street may still be nil.

Equally an aside, if you are also excavation through nested objects using dot annotation, you tin can do this safely in Ruby two.three besides, using the safe navigation operator. So, rather than calling

          street = user.address.street        

and getting a NoMethodError: undefined method street for cypher:NilClass, you can now call.

          street = user&.address&.street        

The higher up will now deed the same every bit using dig. If the address is cypher then street will be cypher and y'all will need to handle the goose egg when yous later refer to the street. If all the objects are present, street will be assigned correctly.

While this suppresses errors from being shown to the user, if it nevertheless impacts user experience, yous might want to create an internal error to track either in your logs or in an error tracking system like Rollbar and so y'all have visibility to fix the trouble.

If you are not using Ruddy two.iii or above you lot can achieve the aforementioned as higher up using the ruby_dig precious stone{:target="_blank"} and ActiveSupport's try{:target="_blank"} to accomplish similar results.

3. ActionController::InvalidAuthenticityToken

Number three on our list requires conscientious consideration as information technology is related to our awarding's security. ActionController::InvalidAuthenticityToken will be raised when a Postal service, PUT, PATCH, or DELETE asking is missing or has an incorrect CSRF (Cross Site Request Forgery) token.

CSRF is a potential vulnerability in web applications in which a malicious site makes a request to your application on behalf of an unaware user. If the user is logged in their session cookies will be sent along with the request and the attacker can execute commands equally the user.

Runway mitigates CSRF attacks{:target="_blank"} by including a secure token in all forms that is known and verified past the site, but can't be known past a third party. This is performed by the familiar ApplicationController line

          form ApplicationController < ActionController::Base   protect_from_forgery with: :exception stop        

Then, if your production application is raising ActionController::InvalidAuthenticityToken errors it could mean that an attacker is targeting the users of your site, but the Track security measures are keeping you lot safe.

There are other reasons you may be unintentionally receiving this error though.

Ajax

For example, if y'all are making Ajax requests from your forepart, you lot need to ensure y'all are including the CSRF token within the request. If y'all are using jQuery and the congenital in Rails unobtrusive scripting adapter{:target="_blank"} and so this is already handled for you. If yous desire to handle Ajax another style, say using the Fetch API{:target="_blank"}, y'all'll need to ensure you include the CSRF token. For either approach, you need to make sure your application layout includes the CSRF meta tag in the <head> of the document:

          <%= csrf_meta_tags %>        

This prints out a meta tag that looks like this:

          <meta proper name='csrf-token' content='THE-TOKEN'>        

When making an Ajax request, read the meta tag content and add information technology to the headers equally the X-CSRF-Token header.

          const csrfToken = document.querySelector('[name="csrf-token"]').getAttribute('content'); fetch('/posts', {   method: 'POST',   body: JSON.stringify(body),   headers: {     'Content-Blazon': 'application/json'     'X-CSRF-Token': csrfToken   } ).and then(role(response) {   // handle response });        

Webhooks/APIs

Sometimes there are valid reasons to plough off the CSRF protection. If you expect to receive incoming Mail requests to certain URLs in your application from third parties, you won't want to block them on the ground of CSRF. You might be in this position if you are building an API for third party developers or if yous expect to receive incoming webhooks from a service.

You can turn off CSRF protection, merely make sure you are whitelisting the endpoints you know don't need this kind of protection. Y'all can do and so in a controller by skipping the authentication:

          form ApiController < ApplicationController   skip_before_action :verify_authenticity_token end        

If you lot are accepting incoming webhooks, you should be able to verify that the asking came from a trusted source in place of verifying the CSRF token.

4. Net::ReadTimeout

The Cyberspace::ReadTimeout is raised when information technology takes Ruby longer to read data from a socket than the read_timeout value, which is 60 seconds by default. This error tin be raised if you are using Net::HTTP, open-uri or HTTParty{:target="_blank"} to make HTTP requests.

Notably, this doesn't mean that an mistake will exist thrown if the request itself takes longer than the read_timeout value, just that if a particular read takes longer than the read_timeout. You tin read more than about Net::HTTP and timeouts from Felipe Philipp{:target="_blank"}.

At that place are a couple of things nosotros tin do to stop getting Internet::ReadTimeout errors. In one case you empathise the HTTP requests that are throwing the error you tin can try to conform the read_timeout value to something more sensible. As in the commodity above, if the server you are making the request to takes a long time to put together a response before sending it all at one time, you volition want a longer read_timeout value. If the server returns the response in chunks and then y'all will want a shorter read_timeout.

You can set read_timeout past setting a value in seconds on the corresponding HTTP client you are using:

with Net::HTTP

          http = Internet::HTTP.new(host, port, read_timout: 10)        

with open-uri

          open(url, read_timeout: ten)        

with HTTParty

          HTTParty.get(url, read_timeout: 10)        

You lot can't always trust some other server to reply within your expected timeouts. If you can run the HTTP request in a background task with retries, like Sidekiq{:target="_blank"}, that can mitigate the errors from the other server. You volition need to handle the case where the server never responds in time though.

If you need to run the HTTP asking within a controller action, then you should be rescuing the Internet::ReadTimeout fault and providing your user with an alternative experience and tracking it in your error monitoring solution. For example:

          def show   @post = Post.find(params[:slug])   begin     @comments = HTTParty.become(COMMENTS_SERVER, read_timeout: 10)   rescue Net::ReadTimeout => east     @comments = []   @error_message = "Comments couldn't be retrieved, please try again later."     Rollbar.error(eastward);   end end        

5. ActiveRecord::RecordNotUnique: PG::UniqueViolation

This error message is specifically for PostgreSQL databases, but the ActiveRecord adapters for MySQL and SQLite volition throw similar errors. The issue here is that a database tabular array in your application has a unique index on one or more fields and a transaction has been sent to the database that violates that alphabetize. This is a hard trouble to solve completely, but let's wait at the low hanging fruit first.

Imagine you've created a User model and, in the migration, ensured that the user'southward e-mail accost is unique. The migration might wait like this:

          form CreateUsers < ActiveRecord::Migration[5.1]   def modify     create_table :users do |t|       t.string :e-mail       t.timestamps     cease     add_index :users, :email, unique: truthful   finish terminate        

To avoid most instances of ActiveRecord::RecordNotUnique you should add a uniqueness validation to your User model too.

          form User < ApplicationRecord   validates_uniqueness_of :email end        

Without this validation, all email addresses volition exist sent to the database when calling User#save and will raise an error if they aren't unique. Even so, the validation tin can't guarantee that this won't happen. For a total caption you should read the concurrency and integrity department of the validates_uniqueness_of documentation{:target="_blank"}. The quick description is that the Track uniqueness cheque is prone to race conditions based on the club of operation for multiple requests. Being a race condition, this also makes this mistake difficult to reproduce locally.

To bargain with this fault requires some context. If the errors are caused by a race status, that may be because a user has submitted a grade twice by mistake. We tin attempt to mitigate that issue with a flake of JavaScript to disable the submit button after the first click. Something a scrap like this is a offset:

          const forms = document.querySelectorAll('form'); Assortment.from(forms).forEach((form) => {   form.addEventListener('submit', (event) => {     const buttons = course.querySelectorAll('push, input[type=submit]')     Assortment.from(buttons).forEach((button) => {       push.setAttribute('disabled', 'disabled');     });   }); });        

This tip on Coderwall to use ActiveRecord's first_or_create! along with a rescue and retry{:target="_blank"} when the fault is raised is a corking workaround. Y'all should go on to log the error with your error monitoring solution then that you maintain visibility on it.

          def cocky.set_flag( user_id, flag )   # Making certain we just retry ii times   tries ||= 2   flag = UserResourceFlag.where( :user_id => user_id , :flag => flag).first_or_create! rescue ActiveRecord::RecordNotUnique => e   Rollbar.error(e)   retry unless (tries -= 1).zero? end        

ActiveRecord::RecordNotUnique might seem like an border case, but it's here at number 5 in this pinnacle 10, and then it is definitely worth because with regard to your user experience.

6. NoMethodError: undefined method 'id' for nil:NilClass

NoMethodError appears once again, though this fourth dimension with a different explanatory message. This fault usually sneaks up around the create action for an object with a relation. The happy path—creating the object successfully—ordinarily works, but this error pops upwards when validations fail. Let's have a look at an example.

Here's a controller with actions to create an application for a course.

          class CourseApplicationsController < ApplicationController   def new     @course_application = CourseApplication.new     @grade = Grade.notice(params[:course_id])   terminate   def create     @course_application = CourseApplication.new(course_application_params)     if @course_application.save       redirect_to @course_application, notice: 'Application submitted'     else       render :new     end   end   private   def course_application_params     params.require(:course_application).allow(:name, :email, :course_id)   cease cease        

The grade in the new template looks a bit like this:

          <%= form_for [@grade, @course_application] do |ca| %>   <%# residuum of the course %> <% end %>        

The problem hither is when you call return :new from the create activeness, the @course instance variable wasn't set. Y'all demand to ensure that all the objects the new template needs are initialised in the create action as well. To fix this fault, nosotros'd update the create action to look like this:

                      def create     @course_application = CourseApplication.new(course_application_params)     if @course_application.save       redirect_to @course_application, notice: 'Application submitted'     else       @course = Course.notice(params[:course_id])       render :new     end   end        

Check out this article if y'all are interested in learning more about the bug with nil in Rails and how to avert them{:target="_blank"}.

7. ActionController::ParameterMissing

This error is part of the Track stiff parameters{:target="_blank"} implementation. It does not manifest every bit a 500 error though—it is rescued by ActionController::Base and returned as a 400 Bad Request.

The full error might wait like this:

          ActionController::ParameterMissing: param is missing or the value is empty: user        

This will be accompanied by a controller that might look a scrap like this:

          class UsersController < ApplicationController   def create     @user = User.new(user_params)     if @user.relieve       redirect_to @user     else       render :new     end   terminate   private   def user_params     params.crave(:user).permit(:name, :electronic mail)   end stop        

The params.require(:user) means that if user_params is called and params does not have a :user key or params[:user] is empty, ActionController::ParameterMissing will be raised.

If you are building an application to be used via a web forepart end and yous have built a form to correctly post the user parameters to this activity, then a missing user parameter probably means someone is messing with your application. If that is the example, a 400 Bad Request response is likely the best response as you don't need to cater to potentially malicious users.

If your awarding is providing an API, then 400 Bad Request is also an appropriate response to a missing parameter.

viii. ActionView::Template::Fault: undefined local variable or method

This is our but ActionView error in the peak ten and that'due south a good sign. The less piece of work the views have to do to render templates the better. Less work leads to fewer errors. Nosotros're withal left with this mistake though, in which a variable or method you await to be just doesn't.

This crops upwards most commonly in partials, probably due to the many dissimilar ways you lot can include a fractional with local variables on a page. If you take a partial chosen _post.html.erb that contains a web log post template and an instance variable @mail service prepare in your controller, so you can render the partial like this:

          <%= return @post %>        

or

          <%= render 'post', postal service: @post %>        

or

          <%= render fractional: 'post', locals: { mail: @post } %>        

Runway likes to give u.s.a. plenty of options to piece of work with, only the second and third options hither are where confusion tin can creep in. Trying to render a fractional like:

          <%= return 'post', locals: { mail service: @post } %>        

or

          <%= render partial: 'post', post: @post %>        

will leave you with an undefined local variable or method. To avoid this, stay consistent and e'er render partials with the explicit partial syntax, expressing the local variables in a locals hash:

          <%= return fractional: 'post', locals: { mail service: @postal service } %>        

There is 1 other identify you can skid up with local variables in partials. If yous only sometimes pass a variable to a partial, testing for that variable is different within a fractional to regular Ruby code. If, for example, you update the mail fractional higher up to take a local variable that tells you whether to show a header image in the partial, you would render the partial similar so:

          <%= render fractional: 'postal service', locals: { post: @post, show_header_image: truthful } %>        

Then the partial itself might wait like this:

          <h1><%= @post.title %></h1> <%= image_tag(@post.header_image) if show_header_image %> <!-- and and then on -->        

This will work fine when you pass the show_header_image local variable, but when you call

          <%= return partial: 'post', locals: { post: @post } %>        

it volition neglect with an undefined local variable. To test for the being of a local variable inside a fractional, you should check whether it is defined before you use information technology.

          <%= image_tag(@post.header_image) if defined?(show_header_image) && show_header_image %>        

Even ameliorate though, there is a hash called local_assigns within a fractional that we tin employ instead.

          <%= image_tag(@post.header_image) if local_assigns[:show_header_image] %>        

For variables that aren't booleans, we tin can use other hash methods like fetch to handle this gracefully. Using show_header_image as an example, this scenario would also work:

          <%= image_tag(@post.header_image) if local_assigns.fetch(:show_header_image, faux) %>        

Overall, sentinel out when you lot are passing variables to partials!

nine. ActionController::UnknownFormat

This error, like the ActionController::InvalidAuthenticityToken, is one that could be caused by careless or malicious users rather than your awarding. If you've built an application in which the actions respond with HTML templates and someone requests the JSON version of the page, y'all will find this mistake in your logs, looking a bit like this:

          ActionController::UnknownFormat (BlogPostsController#alphabetize is missing a template for this request format and variant. request.formats: ["awarding/json"] asking.variant: []):        

The user will receive a 406 Not Acceptable response. In this example they'll see this mistake because you haven't divers a template for this response. This is a reasonable response, since if y'all don't want to return JSON, their asking was non adequate.

You may, however, have congenital your Rails awarding to reply to regular HTML requests and more than API-like JSON requests in the same controller. Once you start doing this, you define the formats you do want to respond to and any formats that fall exterior of that will also cause an ActionController::UnknownFormat, returning a 406 status. Let'south say you have a blog posts index that looks like:

          form BlogPostsController < ApplicationController   def index     respond_to practice |format|       format.html { render :index }     terminate   cease end        

Making a request for the JSON would outcome in the 406 response and your logs would prove this less expressive error:

          ActionController::UnknownFormat (ActionController::UnknownFormat):        

The error this fourth dimension doesn't complain nigh a lack of a template—it's an intentional mistake because you have divers the only format to respond to is HTML. What if this is unintentional though?

Information technology's mutual to miss a format in a response that you intend to support. Consider an action in which y'all desire to reply to HTML and JSON requests when creating a blog mail, so that your page can back up an Ajax request. It might look like this:

          form BlogPostsController < ApplicationController   def create     @blog_post = BlogPost.new(blog_post_params)     respond_to do |format|       if @blog_post.salve         format.html { redirect blog_post_path(@blog_post) }         format.json { render json: @blog_post.to_json }       else         render :new       cease     stop   end end        

The fault here is raised in the case of the blog postal service failing validations and not saving. Within the respond_to block, yous need to call render within the scope of the format blocks. Rewriting this to accommodate for failure would look like:

          class BlogPostsController < ApplicationController   def create     @blog_post = BlogPost.new(blog_post_params)     respond_to practise |format|       if @blog_post.salve         format.html { redirect blog_post_path(@blog_post) }         format.json { return json: @blog_post.to_json }       else         format.html { render :new }         format.json { render json: @blog_post.errors.to_json }       end     end   end cease        

At present all of the formats are covered and there won't be any more than unintentional ActionController::UnknownFormat exceptions.

10. StandardError: An fault has occurred, this and all afterwards migrations canceled

This final particular on our tiptop 10 disappoints me slightly. StandardError{:target="_blank"} is the base of operations error class that all other errors should inherit from, so using it here makes the fault feel very generic, when in reality it is an error that has happened during a database migration. I would prefer to come across this fault as a descendent of the ActiveRecord::MigrationError. But I digress…

At that place are a number of things that can cause a migration to fail. Your migrations may have gotten out of sync with your actual production database, for case. In that case, you're going to have to go excavation around to find out what has happened and set up information technology.

In that location is ane thing that should be covered hither though: information migrations.

If you need to add together or calculate some data for all the objects in a table y'all might think that a data migration is a good idea. As an case, if you wanted to add a full proper noun field to a user model that included their showtime and terminal name (not a likely modify, only expert enough for a uncomplicated example), y'all might write a migration like this:

          course AddFullNameToUser < ActiveRecord::Migration   def up     add_column :users, :full_name, :string     User.find_each exercise |user|       user.full_name = "#{user.first_name} #{user.last_name}"       user.save!     end   end   def downwards     remove_column :users, :full_name   terminate end        

There are a lot of problems with this scenario. If in that location is a user with corrupt data in y x xour set, the user.save! command will throw an error and abolish the migration. Secondly, in production y'all may have a lot of users, which ways the database would have a long time to migrate, peradventure keeping your application offline for the entire fourth dimension. Finally, as your application changes over fourth dimension, you might remove or rename the User model, which would crusade this migration to fail. Some advice suggests that you ascertain a User model inside the migration to avoid this. For even greater safety, Elle Meredith advises united states of america to avoid information migrations inside ActiveRecord migrations{:target="_blank"} completely and build out temporary data migration tasks instead.

Changing information outside of the migration ensures you do a few things. Most importantly, it makes y'all consider how your model works if the data is not present. In our full name example, you would likely define an accessor for the full_name property that could reply if the data was available. If information technology's non, and so build the total name by concatenating the constituent parts.

          form User < ApplicationRecord   def full_name     @full_name || "#{first_name} #{last_name}"   end cease        

Running a data migration as a separate task also means the deploy no longer relies on this data changing beyond the production database. Elle'south article has more reasons why this works better and includes best practices on writing the task as well.

Determination

The most popular Runway errors can come up from anywhere inside the application. In this article we've seen common errors manifested in the model, the view, and the controller. Some of the errors aren't necessarily anything to worry about and are simply protecting your application. Others should be caught as presently every bit possible and stamped out.

Nevertheless, information technology'due south proficient to rail how oftentimes these errors happen. This leads to improve visibility into bug that are affecting your users or application security, so you tin ready them quickly. Otherwise, these error messages will exist shown to the user, simply the technology and production management teams will take no thought until users complain to support.

We promise you learned something new and are better equipped to avoid these errors in the future. However, even with the best practices, unexpected errors do pop upwards in production. It'south important to have visibility into errors that affect your users, and to have proficient tools to solve them quickly.

Rollbar gives y'all visibility to product Crimson errors, which offers more than context to solve them quickly, including form validation errors, person tracking, kicking errors and more. Check out Rollbar'southward full listing of features and Ruby-red SDK documentation.


If you oasis't already, sign up for a 14-day free trial of Rollbar and let us help you take command of impactful Rail errors.

waltersupood1951.blogspot.com

Source: https://rollbar.com/blog/top-10-errors-from-1000-ruby-on-rails-projects-and-how-to-avoid-them/

0 Response to "Ask Again Later Undefined Method for Nil nilclass"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel