Зарегистрируйтесь, чтобы продолжить обучение

CRUD Ruby On Rails

Несмотря на огромное число разнообразных сайтов, практически всю веб-разработку можно свести к CRUD-операциям. В этом уроке мы познакомимся с ними подробнее.

Что такое CRUD

CRUD — это широко распространенный термин, означающий четыре стандартные операции над любой сущностью. Рассмотрим такой пример для статей:

  • Создание (Create) — добавление новой статьи.
  • Чтение (Read) — просмотр статьи пользователями сайта или в административном интерфейсе.
  • Обновление (Update) — редактирование содержимого статьи, изменение заголовка или категории.
  • Удаление (Delete) — удаление статьи из базы данных.

Точно так же можно расписать действия над любыми другими ресурсами: комментариями к статьям, тегами, авторами и так далее. Чтобы создать полный CRUD для статей, нужно выполнить следующие действия:

  • Создать сущность в коде (как правило, это класс).
  • Добавить таблицу в базу данных для хранения статей.
  • Написать тесты для проверки обработчиков статей.
  • Добавить обработчики для выполнения CRUD операций.
  • Добавить шаблоны для отображения статей на сайте.

Ниже мы пройдемся по всему процессу создания CRUD статьи (сущность Article).

Начнем с роутинга. Полный CRUD для статей включает минимум семь маршрутов:

Метод Маршрут Шаблон Описание
GET /articles articles/index.html.erb Список статей
GET /articles/{id} articles/show.html.erb Просмотр статьи
GET /articles/new articles/new.html.erb Форма создания новой статьи
POST /articles Создание новой статьи
GET /articles/{id}/edit articles/edit.html.erb Форма редактирования статьи
PATCH/PUT /articles/{id} Обновление статьи
DELETE /articles/{id} Удаление статьи

Такое соглашение об именовании маршрутов изначально появилось в Ruby On Rails, а затем его адаптировали во многих других.

Ресурсный роутинг — это механизм в Ruby on Rails, который позволяет легко создавать маршруты для стандартных операций CRUD (Создание, Чтение, Обновление, Удаление) для ресурсов, таких как модели. Он значительно упрощает процесс определения маршрутов, так как автоматически создает все необходимые маршруты для работы с ресурсами.

Командой bin/rails g resource мы можем создать новый ресурс и полный набор файлов и кода, необходимых для работы с ресурсом. Давайте разберем, что именно делает эта команда и какие файлы она создает.

bin/rails g resource article title:string body:text
      invoke  active_record
      create    db/migrate/20250116162806_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml
      invoke  controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      invoke    test_unit
      create      test/controllers/articles_controller_test.rb
      invoke    helper
      create      app/helpers/articles_helper.rb
      invoke      test_unit
      invoke  resource_route
      route    resources :articles
  • bin/rails: Это исполняемый файл Rails, который запускает команды в вашем приложении.
  • g: Сокращение от "generate", команда для генерации кода.
  • resource: Указывает, что мы хотитим создать ресурс, который будет включать в себя маршруты, контроллер, представления и миграции.
  • article: Имя ресурса, в данном случае это Article.
  • title:string body:text: Это атрибуты, которые будут добавлены к модели Article. Здесь title будет строковым полем, а body — текстовым полем.

При выполнении этой команды Rails создаст следующие файлы и изменения:

  1. Миграция: Создается файл миграции в db/migrate, который будет содержать код для создания таблицы articles с полями title и body.

    Пример миграции:

    class CreateArticles < ActiveRecord::Migration[6.0]
      def change
        create_table :articles do |t|
          t.string :title
          t.text :body
    
          t.timestamps
        end
      end
    end
    
  2. Модель: Создается файл модели app/models/article.rb, который будет представлять сущность Article.

    Пример модели:

    class Article < ApplicationRecord
    end
    
  3. Контроллер: Создается контроллер app/controllers/articles_controller.rb, который будет обрабатывать запросы, связанные с ресурсом Article.

    class ArticlesController < ApplicationController
    end
    
  4. Представления: Создается директория app/views/articles, в которой будут находиться шаблоны представлений для действий контроллера (index, show, new, edit).

  5. Маршруты: В файл config/routes.rb будет добавлена строка для ресурсного роутинга:

    resources :articles
    

Команда генерации упрощает процесс создания нового ресурса в приложении Ruby on Rails, автоматически генерируя все необходимые компоненты для работы с сущностью. После выполнения этой команды останется только выполнить миграцию базы данных с помощью bin/rails db:migrate и начать использовать созданный ресурс.

Модель была создана пустой, мы можем добавить в нее валидацию присутствия полей:

class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true
end

После генерации ресурса Article с помощью команды bin/rails g resource articles title:string body:text, у нас есть все необходимые компоненты для работы с CRUD операциями. Давайте подробнее рассмотрим каждую из них.

Создание (Create)

Метод Маршрут Метод контроллера
POST /articles create

Создание новой статьи начинается с отображения формы для ввода данных. Когда пользователь заполняет форму и отправляет ее, данные передаются на сервер с помощью POST-запроса.

Пример метода create в контроллере:

class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to @article, notice: 'Статья успешно создана.'
    else
      render :new
    end
  end

  private

  def article_params
    params.require(:article).permit(:title, :body)
  end

end

В этом методе мы создаем новый объект Article, используя параметры, полученные из формы с помощью Strong Params. Strong Parameters — это механизм в Ruby on Rails, который помогает защитить приложение от уязвимостей, связанных с массовым присвоением (mass assignment). Он позволяет явно указывать, какие параметры могут быть использованы для создания или обновления объектов, что предотвращает возможность изменения нежелательных атрибутов.

Форма для создания новой статьи отображается на странице, когда пользователь переходит по маршруту GET /articles/new. В контроллере ArticlesController метод new отвечает за инициализацию нового объекта Article и отображение формы.

class ArticlesController < ApplicationController
  # ...

  def new
    @article = Article.new
  end

  # ...

end

После выполнения метода new(), Rails автоматически рендерит шаблон app/views/articles/new.html.erb, который содержит форму для создания новой статьи:

<h1>Создать новую статью</h1>

<%= form_with model: @article, local: true do |form| %>
  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@article.errors.count, "ошибка") %>:</h2>
      <ul>
        <% @article.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div>
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :body %>
    <%= form.text_area :body %>
  </div>

  <div>
    <%= form.submit "Создать" %>
  </div>
<% end %><h1>Создать новую статью</h1>
<%= link_to 'Назад к списку', articles_path %>

Здесь Используется хелпер form_with, который создает форму для объекта @article. Если при валидации возникли ошибки, они будут отображены в верхней части формы, что позволяет пользователю увидеть, что нужно исправить. Поля формы (title и body) автоматически связываются с атрибутами объекта @article.

Если сохранение прошло успешно, происходит перенаправление на страницу статьи. В противном случае отображается форма с ошибками.

Чтение (Read)

Метод Маршрут Метод контроллера
GET /articles index
GET /articles/{id} show

Чтение статей включает в себя два действия: отображение списка всех статей и просмотр конкретной статьи.

Пример метода index:

class ArticlesController < ApplicationController
  # ...

  def index
    @articles = Article.all
  end

  # ...
end

Переменная @articles будет доступна в представлении, что позволяет отобразить список статей.

<h1>Список статей</h1>

<table>
  <thead>
    <tr>
      <th>Заголовок</th>
      <th>Действия</th>
    </tr>
  </thead>

  <tbody>
    <% @articles.each do |article| %>
      <tr>
        <td><%= link_to article.title, article %></td>
        <td>
          <%= link_to 'Редактировать', edit_article_path(article) %>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= link_to 'Создать новую статью', new_article_path %>
<%= link_to 'Назад к списку', articles_path %>

Пример метода show:

class ArticlesController < ApplicationController
  # ...

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

  # ...
end

Метод index получает все статьи из базы данных и передает их в представление. Метод show находит конкретную статью по ID и также передает ее в представление.

Обновление (Update)

Метод Маршрут Метод контроллера
PATCH/PUT /articles/{id} update

Обновление статьи начинается с отображения формы редактирования, которая заполняется текущими данными статьи. После внесения изменений и отправки формы данные передаются на сервер с помощью PATCH или PUT-запроса.

Пример метода update:

class ArticlesController < ApplicationController
  # ...
  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      redirect_to @article, notice: 'Статья успешно обновлена.'
    else
      render :edit
    end
  end

  # ...
end

В этом методе мы находим статью по ID и обновляем ее с новыми параметрами. Если обновление прошло успешно, происходит перенаправление на страницу статьи. В противном случае отображается форма редактирования с ошибками.

<h1>Редактировать статью</h1>

<%= form_with model: @article, local: true do |form| %>
  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@article.errors.count, "ошибка") %>:</h2>
      <ul>
        <% @article.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div>
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :body %>
    <%= form.text_area :body %>
  </div>

  <div>
    <%= form.submit "Обновить" %>
  </div>
<% end %>

Если при валидации возникли ошибки, они будут отображены в верхней части формы, что позволяет пользователю увидеть, что нужно исправить. Поля формы (title и body) автоматически заполняются текущими значениями статьи.

Удаление (Delete)

Метод Маршрут Метод контроллера
DELETE /articles/{id} destroy

Удаление статьи происходит по запросу DELETE. Обычно это действие инициируется пользователем через кнопку "Удалить" на странице статьи или в списке статей.

Пример метода destroy:

class ArticlesController < ApplicationController
  # ...

  def destroy
    @article = Article.find(params[:id])
    @article.destroy
    redirect_to articles_path, notice: 'Статья успешно удалена.'
  end

  # ...
end

В этом методе мы находим статью по ID и вызываем метод destroy, чтобы удалить ее из базы данных. После успешного удаления происходит перенаправление на страницу со списком статей.

Чтобы выполнить запрос на удаление ресурса из шаблона, мы должны использовать хелпер link_to с указанием метода :delete. Это позволяет отправить DELETE-запрос на сервер, когда пользователь нажимает на ссылку.

<%= link_to 'Удалить', article, data: { turbo_method: :delete, turbo_confirm: 'Вы уверены, что хотите удалить эту статью?' } %>

Flash

Сообщения flash используются для отображения временных уведомлений пользователям, таких как сообщения об успехе или ошибках после отправки форм или выполнения других действий. Флеш-сообщения передаются в шаблон и там выводятся. После их извлечения хранилище обнуляется.

Флеш-сообщения показываются только на один запрос. После обновления страницы или перехода в другое место они пропадают. Это удобно, так как не нужно следить за их жизненным циклом.

Во многих веб-фреймворках, включая Ruby on Rails, типы флеш-сообщений часто стандартизированы, например:

  • notice или success: для информирования пользователя о том, что действие было выполнено успешно.

  • error для отображения ошибок, связанных с валидацией или другими проблемами. Например, сообщение о том, что введённые данные некорректны.

  • info: Используется для предоставления дополнительной информации пользователю, которая не является ни успешной, ни ошибочной. Например, сообщение о том, что действие будет выполнено позже.

  • warning: для предупреждения пользователя о потенциальных проблемах или рисках, связанных с его действиями.

Пример использования Flash

В контроллере Ruby on Rails мы можем использовать эти типы сообщений следующим образом:

def create
  @article = Article.new(article_params)
  if @article.save
    redirect_to @article, notice: 'Статья успешно создана.'
  else
    flash.now[:alert] = 'Ошибка при создании статьи. Пожалуйста, проверьте данные.'
    render :new
  end
end

Чтобы вывести flash-сообщения в нашем приложении на Ruby on Rails, добавим соответствующий код в представление. Обычно это делается в основном макете приложения, чтобы сообщения отображались на всех страницах:

app/views/layouts/application.html.erb:

<% if flash.any? %>
  <% flash.each do |key, value| %>
    <div class="<%= key %>"><%= value %></div>
  <% end %>
<% end %>

Собираем все вместе

Итоговый контроллер: Полный разбор элементов CRUD

Собираем все элементы CRUD в итоговом контроллере ArticlesController, который управляет статьями в нашем приложении. Контроллер включает следующие действия:

  • create: Создает новую статью, проверяет наличие ошибок и перенаправляет пользователя на страницу статьи или возвращает форму с сообщением об ошибках.
  • new: Инициализирует новый объект статьи для отображения формы создания.
  • index: Получает все статьи и отображает их в списке.
  • show: Находит и отображает конкретную статью по ее идентификатору.
  • edit: Находит статью для редактирования и отображает форму.
  • update: Обновляет существующую статью, проверяет наличие ошибок и перенаправляет пользователя или возвращает форму с сообщениями об ошибках.
  • destroy: Удаляет статью и перенаправляет пользователя на список статей или возвращает сообщение об ошибке, если удаление не удалось.
class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params)
    if @article.save
      flash[:notice] = 'Статья успешно создана'
      redirect_to @article
    else
      flash[:notice] = 'Упс, поправьте ошибки в форме'
      render :new, status: :unprocessable_entity
    end
  end

  def new
    @article = Article.new
  end

  def index
    @articles = Article.all
  end

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

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

  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      flash[:notice] = 'Статья успешно обновлена'
      redirect_to @article
    else
      flash[:notice] = 'Упс, поправьте ошибки в форме'
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @article = Article.find(params[:id])
    if @article.destroy
      flash[:notice] = 'Статья успешно удалена'
      redirect_to articles_path
    else
      flash[:notice] = 'Упс, не получилось удалить статью'
      redirect_back fallback_location: :articles_path
    end
  end

  private

  def article_params
    params.require(:article).permit(:title, :body)
  end
end

Контроллер также включает метод article_params, который использует Strong Parameters для обеспечения безопасности, разрешая только определенные параметры для массового присвоения.

Обработка HTTP-ошибок

Обработка HTTP-ошибок позволяет обеспечить пользователям понятные и информативные сообщения об ошибках. В Ruby on Rails существует несколько способов обработки ошибок, которые позволяют разработчикам управлять различными ситуациями, такими как отсутствие запрашиваемых ресурсов, ошибки валидации и внутренние серверные ошибки.

Рассмотрим, как настроить маршруты для обработки ошибок, создать контроллер для управления этими ошибками и использовать механизмы Rails для перенаправления пользователей на соответствующие страницы ошибок.

Настройка обработки ошибок

  1. В Ruby on Rails настройка config.exceptions_app = routes в config/application.rb позволяет нам обрабатывать ошибки через маршруты приложения, что дает возможность создавать свои страницы ошибок.

    В файле config/application.rb добавим следующую строку:

      config.exceptions_app = routes
    

    Это указывает фреймворку использовать маршруты приложения для обработки исключений.

  2. В файле config/routes.rb добавим маршруты для обработки ошибок:

      Rails.application.routes.draw do
        get '/404', to: 'errors#not_found', as: :not_found_errors
        get '/500', to: 'errors#server_error', as: :server_error_errors
    
        # Обработка всех остальных маршрутов
        match '*unmatched', to: 'errors#not_found', via: :all
      end
    
  3. Создадим контроллер ErrorsController в соответствующем файле app/controllers/errors_controller.rb:

      class ErrorsController < ApplicationController
        def not_found
          render status: :not_found
        end
    
        def server_error
          render status: :internal_server_error
        end
      end
    
  4. Создадим директорию app/views/errors и добавим в нее шаблоны для ошибок:

    app/views/errors/not_found.html.erb:

      <!-- app/views/errors/not_found.html.erb -->
      <h1>404 - Страница не найдена</h1>
      <p>Извините, но запрашиваемая страница не существует.</p>
      <%= link_to 'Вернуться на главную', root_path %>
    

    app/views/errors/server_error.html.erb:

      <h1>500 - Внутренняя ошибка сервера</h1>
      <p>Извините, произошла ошибка на сервере. Пожалуйста, попробуйте позже.</p>
      <%= link_to 'Вернуться на главную', root_path %>
    

Поведение вывода ошибок зависит от конфигурации окружения, в котором работает приложение. Если config.consider_all_requests_local установлено в true (что является значением по умолчанию в development-среде), Rails будет показывать полные трассировки стека и подробные сообщения об ошибках в браузере. Это позволяет видеть, что пошло не так, и быстро исправлять ошибки.

В production-среде consider_all_requests_local обычно установлено в false. Rails не будет показывать полные трассировки стека. Вместо этого фреймворк будет отображать стандартные страницы ошибок (например, 404 или 500) или наши страницы ошибок.

Изменить поведение вывода ошибок в разных окружениях, можно изменив config/environments/.rb* файлы. Например, в config/environments/development.rb:

require 'active_support/core_ext/integer/time'

Rails.application.configure do
  # ...

  # Теперь будут выводиться страницы из представлений views/errors/*
  config.consider_all_requests_local = false

  # ...
end

Теперь наше приложение настроено для обработки ошибок через маршруты, что позволяет предоставлять пользователям более информативные и стилизованные страницы ошибок. Это улучшает взаимодействие с приложением и делает его более удобным для пользователей. Мы можем дополнительно настроить стили и содержание этих страниц в зависимости от требований и дизайна приложения.

Заключение

Мы изучили создания CRUD-сущности в Ruby on Rails, мы рассмотрели ключевые этапы, включая настройку ресурсного роутинга, создание контроллеров и представлений, а также обработку HTTP-ошибок. Эти аспекты обеспечивают функциональность, удобство использования и надежность веб-приложения.


Самостоятельная работа

Создайте новый Rails-проект для экспериментов, если его еще нет.

  1. Повторите примеры из теории. С помощью генераторов создайте CRUD для сущности Article. У сущности должны быть следующие поля

    • title - текстовая строка, минимум 10 символов
    • body - текст. Минимум 200 символов
    • author - текстовая строка, имя автора
    • published? - поле-флаг с признаком публикации
  2. На главную страницу добавьте ссылку на список статей.


Дополнительные материалы

  1. Getting Started with Rails - CRUD
  2. Rails Guides - Rails Routing from the Outside In
  3. Как использовать faker для заполнения таблиц в Rails?
  4. Faker
  5. CRUD глаголы и экшены

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff