Article updates on website built with Ruby

We have revealed the “CR” part of CRUD. Now let’s focus on the “U” part, updating articles.

The first step is to add an edit action to the ArticlesController, usually between the new and create actions, as shown.

def new

  @article = article.new

end

def edit

  @article = Article.find(params[:id])

end

def create

  @article = Article.new(article_params)

  if @article.save

    redirect_to @article

  else

    render ‘new’

  end

end

The view will contain a form similar to the one we used when creating new articles. Create a file called app/views/articles/edit.html.erb and add the following to it:

<h1>Editing article</h1>

<%= form_with(model: @article, local: true) do |form| %>

  <% if @article.errors.any? %>

    <div id=”error_explanation”>

      <h2>

        <%= pluralize(@article.errors.count, “error”) %> prohibited

        this article from being saved:

      </h2>

      <ul>

        <% @article.errors.full_messages.each do |msg| %>

          <li><%= msg %></li>

        <% end %>

      </ul>

    </div>

  <% end %>

Right now, we’re pointing the form to an update action, which isn’t defined yet, but we’ll do that soon.

Passing an article object to the method will automatically generate a url to submit the edited article form. This option tells Rails that we want this form to be submitted using PATCH, an HTTP method that is expected to be used to update resources according to the REST protocol.

The form_with arguments can be model objects, such as model: @article , which will cause the helper to populate the form with the object’s fields. Passing a symbol (scope: :article) to the namespace just creates the fields, but doesn’t populate them with anything. Read more in the form_with documentation.

Next, we need to create an update action in app/controllers/articles_controller.rb. Add it between the create action and the private method:

The new method, update, is used when you want to update an entry that already exists, and it takes a hash containing the attributes you want to update. As before, if there is an error updating the article, we want to show the form to the user again.

We have reused the article_params method we defined earlier for the create action.

TIP: It is not necessary to pass all attributes in update. For example, if @article.update(title: ‘A new title’) was called, Rails would only update the title attribute, leaving all other attributes untouched.

Finally, we want to show a link to the edit action in the list of all articles, so let’s add it to app/views/articles/index.html.erb next to the “Show” link:

<table>

  <tr>

    <th>Title</th>

    <th>Text</th>

    <thcolspan=”2″></th>

  </tr>

  <% @articles.each do |article| %>

    <tr>

      <td><%= article.title %></td>

      <td><%= article.text %></td>

      <td><%= link_to ‘Show’, article_path(article) %></td>

      <td><%= link_to ‘Edit’, edit_article_path(article) %></td>

    </tr>

  <% end %>

</table>

And also add app/views/articles/show.html.erb to the template so that the “Edit” link is also on the article page. Add the following at the end of the template:

Using Partials to Clean Up Repetition in Views

Our edit page is very similar to the new page, in fact they use the same code to display the form. Let’s remove this duplication by using a view partial. By convention, partial files begin with an underscore.

TIP: For more on partials, see Layouts and Rendering in Rails.

Create a new file app/views/articles/_form.html.erb with the following content:

<%= form_with model: @article, local: true do |form| %>

  <% if @article.errors.any? %>

    <div id=”error_explanation”>

      <h2>

        <%= pluralize(@article.errors.count, “error”) %> prohibited

        this article from being saved:

      </h2>

      <ul>

        <% @article.errors.full_messages.each do |msg| %>

          <li><%= msg %></li>

        <% end %>

      </ul>

    </div>

  <% end %>

Everything except the form_with declaration is the same. The reason you can use this shorter and simpler form_with declaration than other forms is because @article is a resource that matches the full set of resource routes, and Rails is able to determine which URI and method to use. See Resource-oriented style for details on this use of form_with.

Let’s now update the app/views/articles/new.html.erb view to use this new partial, rewriting it completely:

Deleting articles

We are now ready to cover the “D” part of CRUD, deleting from a database. Following the REST convention, the route to remove articles in the bin/rails routes output is as follows:

DELETE /articles/:id(.:format) articles#destroy

The delete routing method must be used for routes that destroy resources. If left as a normal get route, it would be possible to generate the following malicious URLs:

<a href=’http://example.com/articles/1/destroy’>look at this cat!</a>

We’re using the delete method to destroy resources, and this route is associated with a destroy action in app/controllers/articles_controller.rb that doesn’t exist yet. The destroy method is usually the last CRUD action in the controller, and like all public CRUD actions, it must be placed before any private or protected methods.

You can call destroy on Active Record objects when you want to remove them from the database. Note that we don’t need to add a view for this action since we’re redirecting to the index action.

Finally, let’s add a ‘Destroy’ link to the index action template (app/views/articles/index.html.erb), bringing all the links together.

Here we use link_to in a different way. We pass the named route as the second argument, and the options as the other argument. The options method: :delete and data: { confirm: ‘Are you sure?’ } are used as html5 attributes, so when a link is clicked, Rails will first show the user a confirmation dialog and then send the link using the delete method. This is done using the rails-ujs JavaScript file, which is automatically included in the application layout (app/views/layouts/application.html.erb) when the application is generated. Without this file, the confirmation dialog will not be shown.

Confirmation dialog

TIP: Learn more about unobtrusive JavaScript in the Working with JavaScript in Rails guide.

Congratulations, now you can create, view all and individually, update and delete articles.

TIP: In general, Rails recommends using resource objects instead of manually declaring routes. See Routing in Rails for more information on routing.

Leave a Reply

Your email address will not be published.