DEV Community

loading...

Validations and displaying messages in Rails

rwparrish profile image rwparrish ・5 min read

In this blog, I would like to share my process for setting validations and displaying messages in Rails. Here are the two general topics I will cover:

  1. How can we make sure that instances of objects get saved to the database the way we want them to? The answer 👉 validations
  2. Once validations are working, how can we display messages letting us know about errors and/or successes? The answer 👉 there are a couple of ways to do this so keep reading to learn more!

Active Record

First, what is Active Record? From the official docs here, it is the M in the MVC (Model-View-Controller) software design pattern. Active Record deals with persisting data, more specifically rich objects. Active record is an ORM (Object Relational Mapping) framework. The docs put it well - "Using ORM, the properties and relationships of the objects in an application can be easily stored and retrieved from a database without writing SQL statements directly and with less overall database access code." Basically, Active Record makes connecting to the database much easier and efficient for Rails developers.

Ok, that bit of background info helps us understand why it makes sense that Active Record would also deal with validating objects before they can be saved to the database to be persisted.

A bit on params

Below I have my params setup to whitelist the data I want. First, I require the top-level key of my params - :article and then I specify which keys within the params I want to permit - :title and :description in this case:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
    render plain: @article
end
Enter fullscreen mode Exit fullscreen mode

In the browser, we see something like this #<Article:0x00007fa47fbe8770>. Let's use the inspect method to take a closer look at this object:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
    render plain: @article.inspect
end
Enter fullscreen mode Exit fullscreen mode

We should see something like this in the browser now:

#<Article id: nil, title: "Testing some stuff", description: "testing some stuff", created_at: nil, updated_at: nil>
Enter fullscreen mode Exit fullscreen mode

Notice that id: nil. This is because we haven't saved this instance of an article object to the database yet. Let's try saving it:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
   article.save
end
Enter fullscreen mode Exit fullscreen mode

Now we can hop into the Rails console by entering rails c in the terminal to verify it has been saved. In the console, try Article.all asking to see all instances of article objects and we should see the most recent article created at the bottom of the list with an id: of some number depending on its place in the database table.

You could also do this:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
    @article.save
    render plain: Article.all.inspect
end
Enter fullscreen mode Exit fullscreen mode

Ok, now we know that our strong_params are functioning and we can save objects to the database. Nice! However, what if we have some validations in mind? Here come those built-in Active Record validation helpers I mentioned earlier.

Built in Active Record Validations

In my model - article.rb file:

class Article < ApplicationRecord
  validates :title, presence: true, length: { minimum: 6, maximum: 100 }
  validates :description, presence: true, length: { minimum: 10, maximum: 300 }
end
Enter fullscreen mode Exit fullscreen mode

Above I specify that the value for the :title and :description keys cannot be empty and that those values should have a certain length.

Back in the controller - articles_controller.rb file:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
    if @article.save
      redirect_to @article
    else 
      render 'new'
    end
end
Enter fullscreen mode Exit fullscreen mode

Ok, if the article can be saved, the user should be redirected to the show view to see it. However, if the validations are not met and the article cannot be saved then the form should re-render - essentially prompting the user to try again. Wouldn't it be nice to display an error message here for the user to better understand what went wrong?

Displaying error messages

First, we try creating a new article that we know cannot be saved. Remembering the validations we setup earlier - maybe the title is left empty and/or the description is too short. In the console try:

article = Article.new
=> #<Article id: nil, title: nil, description: nil, created_at: nil, updated_at: nil>
article.save
=> false
article.errors.full_messages
=> => ["Title can't be blank", "Title is too short (minimum is 6 characters)", "Description can't be blank", "Description is too short (minimum is 10 characters)"]
Enter fullscreen mode Exit fullscreen mode

Chaining the errors and full_messages methods we get an array of messages. We want to iterate over this array and display each message. But where should we do this!? Well, since the "new article input form" is being displayed again when validations are not met we should display the error messages there for the user to see.

In the new.html.erb file:

<% if @article.errors.any? %>
  <h3>The following errors prevented the article from being saved:</h3>
  <ul>
    <% @article.errors.full_messages.each do |msg| %>
     <li><%= msg %></li> 
    <% end %>
  </ul>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Because of the instance variable @articles we have access to each newly submitted article in our view. <% if @article.errors.any? %> checks to see if there are any errors on each new instance - we needn't enter the iteration block unless it is necessary to do so. Then we simply iterate over the array of messages inside erb tags. Be sure to use = in the erb tag where you want the information to be displayed in the browser - <li><%= msg %></li>. The above code produces this in the browser:
Alt Text

Displaying messages using flash

Now, what if the new article is saved successfully? How could we tell the user this?

Back in the articles_controller.rb file:

def create
    @article = Article.new(params.require(:article).permit(:title, :description))
    if @article.save
      flash[:notice] = "This article was saved successfully"
      redirect_to @article
    else 
      render 'new'
    end
end
Enter fullscreen mode Exit fullscreen mode

Above we say if the article is saved successfully to the database, we use flash to pass a temporary message from the create action to the show action. The show action will automatically pass the massage to its view. However, we can do something like this:

In the application.html.erb file:

...

<body>
   <% flash.each do |name, msg| %>
     <%= msg %>
   <% end %>
   <%= yield %>
</body>
Enter fullscreen mode Exit fullscreen mode

Recap

We learned how to:

  1. Implement Active Record built-in validations
  2. Display error messages
  3. Display messages using flash

I hope you found this tutorial to be helpful. As always, please ask questions, leave feedback, and share. Happy coding!

Discussion (0)

pic
Editor guide