Один из моих любимых проектов, над которым я работаю как новый разработчик Ruby on Rails, - это создание личного блога. В Интернете есть несколько качественных руководств, и работа над этим проектом учит множеству интересных основных концепций, включая аутентификацию, авторизацию, миграции, ассоциации и многое другое. Однако после того, как вы создали приложение для ведения блога, естественным следующим шагом будет добавление возможности форматирования контента с помощью форматированного текста, такого как размер шрифта, полужирный, курсив, отступы и т. Д. Цель этой статьи - провести вас через стандартную вводимую форму текстового поля Rails и усовершенствовать ее с помощью функций расширенного текстового формата ActionText.
Общие настройки
Для начала давайте создадим новое приложение Rails, которое я назову actiontext_demo
.
rails new actiontext_demo
Как только это приложение будет сгенерировано, не забудьте записать cd в новый каталог приложения.
cd actiontext_demo
Давайте создадим шаблонный ресурс Post, который мы будем использовать с нашим редактором Rich Text. Эта команда сделает тяжелую работу по созданию нашей модели, миграции, контроллера и представлений для ресурса Post нашего блога (Примечание: вместо того, чтобы включать поле содержимого в нашу команду scaffold, мы будем использовать атрибут виртуального содержимого ActionText, который мы будем настрою позже).
rails generate scaffold Post title:string
На этом этапе давайте настроим нашу базу данных и перенесем нашу таблицу сообщений.
rails db:migrate
В качестве последнего общего шага настройки давайте теперь добавим корневой маршрут для представления индекса нашей публикации в верхнюю часть нашего routes.rb
файла.
Rails.application.routes.draw do root to: "posts#index" resources :posts end
Установка ActionText
Нашим первым конкретным шагом ActionText является установка пакета yarn, который, среди прочего, устанавливает необходимые зависимости JavaScript и генерирует миграции для ActiveStorage и ActionText (чтобы этот конкретный пост был кратким, в этом руководстве будет использоваться таблица ActionText, а выход - с использованием функциональности ActiveStorage. чтобы включить хранение вложений и встраивание изображений в будущую публикацию).
bin/rails action_text:install
После успешной установки вы должны увидеть следующие изменения в application.js
:
app/javascript/packs/application.js require("trix") require("@rails/actiontext")
Кроме того, вам потребуется новая таблица стилей ActionText в вашем application.scss
файле, например:
app/assets/stylesheets/application.scss /* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS * files in this directory. Styles in this file should be added after the last require_* statement. * It is generally better to create a new file per style scope.* *= require_tree . *= require_self */ @import "./actiontext.scss";
Прежде чем двигаться дальше, давайте снова перенесем нашу базу данных, чтобы добавить таблицы ActiveStorage и ActionText в нашу схему БД.
rails db:migrate
Настройка ActionText
Раньше, когда мы создавали нашу исходную миграцию Post с помощью сгенерированного каркаса нашего приложения, мы не использовали поле содержимого в пользу использования виртуального атрибута, доступного нам с помощью ActionText. Мы можем настроить это, добавив следующую строку в нашу модель Post.
app/models/post.rb class Post < ApplicationRecord has_rich_text :content end
Затем мы добавим группу форм ввода rich_text_area
в нашу новую форму публикации.
<div class="field">
<%= form.label :content %>
<%= form.rich_text_area :content %>
</div>
Теперь полный файл должен выглядеть так:
app/views/posts/_form.html.erb <%= form_with(model: post, local: true) do |form| %> <% if post.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2> <ul> <% post.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= form.label :title %> <%= form.text_field :title %> </div> <div class="field"> <%= form.label :content %> <%= form.rich_text_area :content %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>
Теперь мы можем отображать очищенный форматированный текст в наших представлениях для просмотра и индексации.
app/views/posts/show.html.erb <p id="notice"><%= notice %></p> <p> <strong>Title:</strong> <%= @post.title %> </p> <p> <strong>Content:</strong> <%= @post.content %> </p> <%= link_to 'Edit', edit_post_path(@post) %> | <%= link_to 'Back', posts_path %> ... app/views/posts/index.html.erb <p id="notice"><%= notice %></p> <h1>Posts</h1> <table> <thead> <tr> <th>Title</th> <th>Content</th> <th colspan="3"></th> </tr> </thead> <tbody> <% @posts.each do |post| %> <tr> <td><%= post.title %></td> <td><%= post.content %></td> <td><%= link_to 'Show', post %></td> <td><%= link_to 'Edit', edit_post_path(post) %></td> <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </tbody> </table> <br> <%= link_to 'New Post', new_post_path %>
Хотя теперь мы можем видеть потрясающий форматировщик Rich Text Formatter, который дает нам ActionText, если вы попытаетесь создать сообщение прямо сейчас, действие не удастся. Чтобы исправить это, нам нужно разрешить наш виртуальный атрибут :content
в контроллере сообщений следующим образом:
app/controllers/posts_controller.rb def post_params params.require(:post).permit(:title, :content) end
Теперь наш posts_controller.rb
файл должен выглядеть так:
app/controllers/posts_controller.rb class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update, :destroy] # GET /posts # GET /posts.json def index @posts = Post.all end # GET /posts/1 # GET /posts/1.json def show end # GET /posts/new def new @post = Post.new end # GET /posts/1/edit def edit end # POST /posts # POST /posts.json def create @post = Post.new(post_params) respond_to do |format| if @post.save format.html { redirect_to @post, notice: 'Post was successfully created.' } format.json { render :show, status: :created, location: @post } else format.html { render :new } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # PATCH/PUT /posts/1 # PATCH/PUT /posts/1.json def update respond_to do |format| if @post.update(post_params) format.html { redirect_to @post, notice: 'Post was successfully updated.' } format.json { render :show, status: :ok, location: @post } else format.html { render :edit } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # DELETE /posts/1 # DELETE /posts/1.json def destroy @post.destroy respond_to do |format| format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_post @post = Post.find(params[:id]) end # Only allow a list of trusted parameters through. def post_params params.require(:post).permit(:title, :content) end end
В качестве последнего шага для повышения производительности давайте обновим действие index контроллера Post, чтобы использовать вспомогательный метод для предотвращения N + 1 запросов к базе данных.
def index @posts = Post.all.with_rich_text_content end
Заключение
Благодаря ActionText, наше базовое приложение для личного блога сделало важный шаг на пути к тому, чтобы стать увлекательным и эстетичным онлайн-журналом как для разработчиков, так и для читателей. Как вы собираетесь использовать его в своих проектах Ruby on Rails?