The model file, app/models/article.rb is about as simple as it can get:
class Article < ApplicationRecordend
There isn't much to this file - but note that the Article class inherits from ApplicationRecord. ApplicationRecord inherits from ActiveRecord::Base which supplies a great deal of functionality to your Rails models for free, including basic database CRUD (Create, Read, Update, Destroy) operations, data validation, as well as sophisticated search support and the ability to relate multiple models to one another.
Rails includes methods to help you validate the data that you send to models. Open the app/models/article.rb file and edit it:
class Article < ApplicationRecordvalidates :title, presence: true,length: { minimum: 5 }end
These changes will ensure that all articles have a title that is at least five characters long. Rails can validate a variety of conditions in a model, including the presence or uniqueness of columns, their format, and the existence of associated objects. Validations are covered in detail in Active Record Validations.
With the validation now in place, when you call @article.save on an invalid article, it will return false. If you open app/controllers/articles_controller.rb again, you'll notice that we don't check the result of calling @article.save inside the create action. If @article.save fails in this situation, we need to show the form back to the user. To do this, change the new and createactions inside app/controllers/articles_controller.rb to these:
def new@article = Article.newenddef create@article = Article.new(article_params)if @article.saveredirect_to @articleelserender 'new'endendprivate def article_paramsparams.require(:article).permit(:title, :text)end
The new action is now creating a new instance variable called @article, and you'll see why that is in just a few moments.
Notice that inside the create action we use render instead of redirect_to when save returns false. The render method is used so that the @article object is passed back to the newtemplate when it is rendered. This rendering is done within the same request as the form submission, whereas the redirect_to will tell the browser to issue another request.
If you reload http://localhost:3000/articles/new and try to save an article without a title, Rails will send you back to the form, but that's not very useful. You need to tell the user that something went wrong. To do that, you'll modify app/views/articles/new.html.erb to check for error messages:
<%= form_with scope: :article, url: articles_path, local: true do |form| %><% if @article.errors.any? %><div id="error_explanation"><h2><%= pluralize(@article.errors.count, "error") %> prohibitedthis article from being saved:</h2><ul><% @article.errors.full_messages.each do |msg| %><li><%= msg %></li><% end %></ul></div><% end %><p><%= form.label :title %><br><%= form.text_field :title %></p><p><%= form.label :text %><br><%= form.text_area :text %></p><p><%= form.submit %></p><% end %><%= link_to 'Back', articles_path %>
A few things are going on. We check if there are any errors with @article.errors.any?, and in that case we show a list of all errors with @article.errors.full_messages.
pluralize is a rails helper that takes a number and a string as its arguments. If the number is greater than one, the string will be automatically pluralized.
The reason why we added @article = Article.new in the ArticlesController is that otherwise @article would be nil in our view, and calling @article.errors.any? would throw an error.
Rails automatically wraps fields that contain an error with a div with class field_with_errors. You can define a css rule to make them standout.
Now you'll get a nice error message when saving an article without title when you attempt to do just that on the new article form http://localhost:3000/articles/new: