Как использовать и настраивать сообщения и типы Rails Flash

Для этого проекта нам понадобятся следующие ингредиенты:

  1. Новый проект Rails 7 rails new flash_msg --css=tailwind --javascript=esbuild
  2. Ваша любимая IDE
  3. Создайте шаблон Post с помощью следующей команды: rails g scaffold Post title:string msg:text
  4. Обновите корень, чтобы по умолчанию использовался posts#index, добавив следующую строку в файл routes.rb root "posts#index"
  5. Запустите миграцию для создания таблицы (в этом проекте используется SQLite, но вы можете перейти на PostgreSQL или MySQL — если да, не забудьте обновить Gemfile или добавить — базу данных при создании проекта на шаге 1)

или просто возьмите исходники с github: https://github.com/spaquet/rails-flash-msg

Давайте сделаем его лучше, так как стандартная конфигурация размещает все элементы в верхней левой части экрана.

Улучшить общий внешний вид:

Приложение.html.erb

<div class="max-w-6xl pt-4 mx-auto">
   <%= yield %>
</div>

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

Application.tailwind.css

Давайте позаботимся о полях формы. Так как этот компонент будет использоваться везде в приложении, давайте добавим CSS в application.tailwind.css и создадим класс для определения общего стиля для всех полей.

@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
  .form-field {
    @apply border border-slate-300 focus:border-slate-900 p-2;
  }
}

Теперь нам просто нужно отредактировать часть, используемую формой _form.html.erb, расположенную в папке app/views/posts.

Тада! Наша форма теперь выглядит немного лучше. По крайней мере, мы можем видеть, где находятся поля:

Давайте теперь сосредоточим наше внимание на флеш-сообщениях.

Вспышка, вспышка и еще раз вспышка

Если вы откроете файл index.html.erb или show.html.erb в каталоге app/views/posts, вы заметите, что их самая первая строка содержит следующий фрагмент кода:

<p style="color: green"><%= notice %></p>

Теперь это немного сокращает, так как отображает только флэш-сообщения типа уведомления. Но перед этим давайте проверим, как срабатывает это сообщение.

Откройте posts_controller.rb в папке app/views/posts и перейдите к методу create или update. .

format.html { redirect_to post_url(@post), notice: "Post was successfully created." }

Как видите, метод redirect_to принимает 2 аргумента. Один — это место для перенаправления, а второй — флэш-сообщение. В этом случае флэш-сообщение имеет тип уведомление и само сообщение, если «Пост был успешно создан»

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

Имея эту информацию, мы можем написать более общий фрагмент флэш-памяти, который будет обрабатывать больше случаев.

<% if flash.any? %>
  <% flash.each do |type, msg| %>
    <div class="py-2 px-4 font-bold msg-<%= type %>">
      <%= msg %>
    </div>
  <% end %>
<% end %>

Удалите <p style="color: green"><%= notice %></p> из файлов index и show (.html.erb), так как мы будем вызывать наш партиал из application.html.erb файл.

<body>
  <div class="max-w-6xl pt-4 mx-auto">
    <%= render "layouts/flash" %>
    <%= yield %>
  </div>
</body>

и, конечно, нам нужно добавить немного CSS в application.tailwind.css

.msg-notice {
  @apply bg-green-300 text-green-900;
}
.msg-alert {
  @apply bg-red-300 text-red-900;
}

Добавление дополнительных типов флэш-памяти

Теперь у нас есть работающее флэш-решение для отображения типов уведомлений и предупреждений. Допустим, мы хотим добавить информационный тип сообщения. Итак, поскольку Flash — это Hash, наша первая интуиция должна заключаться в том, что мы можем добавить их прямо при вызове команды flash, что-то вроде flash[:custom_type]="Message to be displayed" Ну, и да, и нет. Это сработает во многих случаях, но не при использовании метода redirect_to, как указано в: https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/flash.rb.

Пример:

Давайте добавим собственный стиль CSS в файл application.tailwind.css.

.msg-custom {
  @apply bg-yellow-300 text-yellow-900;
}

а затем измените метод create файла posts_controller.rb следующим образом:

# POST /posts or /posts.json
def create
  @post = Post.new(post_params)
respond_to do |format|
    flash[:custom]= "Post was successfully created / Custom message"
    if @post.save
      format.html { redirect_to post_url(@post), success: "Post was successfully created." }
      format.json { render :show, status: :created, location: @post }
    else
      format.html { render :new, status: :unprocessable_entity }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

У нас будет текст «Сообщение успешно создано / Пользовательское сообщение», выделенное желтым цветом на светло-желтом фоне, как только мы создадим новое сообщение, но текст для типа успеха никогда не будет отображаться как Метод redirect_to не разрешает этот тип.

Как мы можем это исправить?

Согласно комментарию в https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal/flash.rb нам нужно объявить наши пользовательские стили, добавив их в список в ApplicationController. .

class ApplicationController < ActionController::Base
  add_flash_types :success, :warning, :info
end

В приведенном выше коде мы определяем 3 новых типа: success, warning и info, которые можно использовать в redirect_to метод.

Следующий код теперь будет работать должным образом (после определения соответствующего стиля CSS в файле application.tailwind.css).

# POST /posts or /posts.json
def create
  @post = Post.new(post_params)
respond_to do |format|
    if @post.save
      format.html { redirect_to post_url(@post), success: "Post was successfully created." }
      format.json { render :show, status: :created, location: @post }
    else
      format.html { render :new, status: :unprocessable_entity }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

Что с рендером?

При вызове render мы остаемся на той же странице. Итак, если нам нужно отобразить ошибку во флэш-сообщении, вызвав flash[:error]="Сообщение об ошибке". Поскольку перенаправления нет, сообщение об ошибке отображаться не будет…

Вот почему существует метод .now, который вызывает flash.now[:error]=”Сообщение об ошибке”. есть, чтобы исправить это. Используя .now, поместите сообщение во флэш-хеш и удалите его, чтобы сообщение не отображалось дважды.

Имейте в виду, что не отображая страницу, вызываемую в redirect_to, флэш-сообщение останется в хэше. Это потенциально означает, что ваши пользователи могут получать противоречивые флэш-сообщения.

Следующее: использование турбо и стимулирования для улучшения отображения флэш-сообщений.