Validations and displaying messages in Rails
Tags: rails, ruby, tutorial
Published: 2020-12-17 18:58:51

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 :point_right: validations
2. Once validations are working, how can we display messages letting us know about errors and/or successes? The answer :point_right:  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](https://guides.rubyonrails.org/active_record_basics.html), it is the M in the [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) (Model-View-Controller) software design pattern. Active Record deals with persisting data, more specifically rich objects. Active record is an [ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) (Object Relational Mapping) framework. The [docs](https://guides.rubyonrails.org/active_record_basics.html) 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`](https://guides.rubyonrails.org/action_controller_overview.html) 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
```
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
```
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>
```
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
```
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
```
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
```
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
```
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)"]
```
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 %>
```
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](https://dev-to-uploads.s3.amazonaws.com/i/r8q37clkbyid9t02oblr.png)

###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
```
Above we say if the article is saved successfully to the database, we use [flash](https://api.rubyonrails.org/classes/ActionDispatch/Flash.html) 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>
```
###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!