Мультиблог на Ruby on Rails. Создание личного кабинета. Урок 9. Часть 2.

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

Редактирование постов

Что касается данного функционала, то с точки зрения безопасности, важно чтобы у нас была проверка, что редактирование статьи производится тем пользователем, который её создал. 

Чтобы отобразить саму форму редактирования, нам нужно в контролере реализовать action edit:

def edit
  @post = Post.find(params[:id])
end

Далее переходим к самой форме редактирования, которая будет располагаться по пути: posts/edit.html.erb И поскольку данный шаблон ничем не будет отличаться от view нового поста, то я решил задействовать в нём ту же самую форму, с помощью метода render:

<% content_for :h1 do %>
Редактирование новой статьи
<% end %>

<% content_for :title do %>
Редактирование новой статьи
<% end %>

<%= render 'form', post: @post %>

Но это мы подгрузили данные в форму, а для того, чтобы сохранить статью, надо реализовать action update. Тут надо понимать, что прежде чем обновить или удалить какую-то статью, сначала необходимо будет получить её объект; за что всегда будет отвечать строка:

@post = Post.find(params[:id])

И вот чтобы не писать данную строку каждый раз, в RoR для этих целей, как возможно вы помните, можно задействовать метод before_action, который будет выполнять определённую функцию перед выполнением определённых action. Нам это операция будет нужна в action edit и update; а в дальнейшем и для show и destroy. Стало быть прописываем:

before_action :set_post, only: [:edit, :update, :show, :destroy]

А вот и сама функция, которую пропишем ниже секции private:

def set_post
  @post = Post.find(params[:id])
end

Соответственно мы удаляем эту строку из метода edit. А метод update в соответствии со всем вышеописанным, теперь будет таким:

def update
  @post.update(post_params)
  redirect_to post_path(@post)
end

Здесь метод update заполняет объект данными из формы, а redirect_to просто редиректит на эту же самую статью. 

Вывод кнопок для редактирования и удаления статьи

Сам код этих кнопок можно разместить прямо в _post.html.erb, что логично, так как эти действия напрямую связаны с той статьёй, к которой они относятся. 

<div class="btn-group">
  <% if current_user != nil and current_user.id == post.user.id %>
    <a class="btn btn-sm btn-info" href="<%= url_for(edit_post_path(post)) %>" role="button">Редактировать</a>
    <a class="btn btn-sm btn-danger" roloe="button" data-toggle="modal" data-target="#post-delete-<%=post.id%>" href="#">Удалить</a>
  <% end %>
</div>

Перед самим выводом кнопок, я прописал проверку на то, авторизован ли пользователь и является ли он автором статьи. В остальном, с кнопкой редактирования всё должно быть понятно и так, данный функционал уже должен работать. А вот по следующей кнопке есть некоторые нюансы... 

Удаление статьи

Пока что мы разместили только кнопку для удаления, которая сама по себе является ссылкой на модальное окно (в котором будет подтверждение на удаление поста). Что касается самого окна, то его можно разместить всё в том же файле _post.html.erb:

<% if current_user != nil and current_user.id == post.user.id %>
  <div id="post-delete-<%= post.id %>" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenter">
    <div class="modal-dialog modal-dialog-centered">
      <div class="modal-content">
        <div class="card-header">
          <div class="modal-body text-center">Вы уверены что хотите это удалить?</div>
          <div class="d-flex justify-content-between align-items-center">
            <%= button_to "Удалить", post, { method: :delete, class: 'btn btn-danger' } %>
            <a class="btn btn-secondary" type="button" data-dismiss="modal">Отмена</a>
          </div>
        </div>
      </div>
    </div>
  </div>
<% end %>

Но у нас удаление пока что работать не будет, так как мы ещё не реализовали метод destroy в соответствующем контролере:

def destroy
  @post.destroy
  redirect_to posts_path
end

Итог работы

Ну и в завершении, в верхнее меню добавим ссылку на наш личный кабинет; при это разместим её только в том случае, если пользователь авторизован, в противном случае - просто выведем ссылки на регистрацию/авторизацию.

<% if user_signed_in? %>
  <li class="nav-item">
    <a class="nav-link" href="<%= url_for(cabinet_path) %>">Личный кабинет</a>
  </li>
<% else %>
  <li class="nav-item">
    <a class="nav-link"href="<%= url_for(new_user_registration_path) %>">Регистрация</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="<%= url_for(new_user_session_path) %>">Авторизация</a>
  </li>
<% end %>

Вот таким вот незамысловатым образом мы реализовали личный кабинет. Все изменения зафиксированы в коммите https://github.com/maclen2007/simple_ruby_blog/commit/24ddcb4839c84363b4d8fd0da6829394c540d8ff