-
Notifications
You must be signed in to change notification settings - Fork 0
/
action-text-overview.html
460 lines (435 loc) · 54.5 KB
/
action-text-overview.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
<meta charset="utf-8">
<meta content="Ruby on Rails, Ruby, Rails, Rails 3, Rails 4, Rails 5, Rails 6, Rails 6.0, Rails 6.1, Rails 7.0, Rails 7.1 руководство, начинающим, самоучитель, manual, мануал, справочник, учебник, примеры, Руби, рельсы" name="keywords"/>
<meta content="Ruby on Rails руководства, учебники, статьи на русском языке" name="description"/>
<meta content="website" property="og:type"/>
<meta content="Rusrails: Обзор Action Text" property="og:title"/>
<meta content="Ruby on Rails руководства, учебники, статьи на русском языке" property="og:description"/>
<meta content="http://localhost:3000/action-text-overview" property="og:url"/>
<meta content="http://rusrails.ru/assets/rusrails.png" property="og:image"/>
<title>
Rusrails: Обзор Action Text
</title>
<link rel="stylesheet" href="/assets/application-f9dfa6ce7fa871006d478e422639671663284ddaa3126cf81ddfe371ac3533c4.css" />
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
<a class="brand" href="/"></a>
<ul class="nav pull-right top-menu">
<li>
<a href="/">Главная</a>
</li>
<li class="dropdown">
<a class="index-popover" href="#">
Содержание
<b class="caret"></b>
</a> <div class="index-popover-content hide">
<ul><li><p><strong>С чего начать?</strong></p><ul><li><a href="/getting-started">Rails для начинающих</a>
</li></ul></li><li><p><strong>Модели</strong></p><ul><li><a href="/active-record-basics">Основы Active Record</a>
</li><li><a href="/active-record-migrations">Миграции Active Record</a>
</li><li><a href="/active-record-validations">Валидации Active Record</a>
</li><li><a href="/active-record-callbacks">Колбэки Active Record</a>
</li><li><a href="/active-record-associations">Связи (ассоциации) Active Record</a>
</li><li><a href="/active-record-querying">Интерфейс запросов Active Record</a>
</li><li><a href="/active-model-basics">Основы Active Model</a>
</li></ul></li><li><p><strong>Вью</strong></p><ul><li><a href="/action-view-overview">Обзор Action View</a>
</li><li><a href="/layouts-and-rendering">Макеты и рендеринг в Rails</a>
</li><li><a href="/action-view-helpers">Хелперы Action View</a>
</li><li><a href="/form-helpers">Хелперы форм в Action View</a>
</li></ul></li><li><p><strong>Контроллеры</strong></p><ul><li><a href="/action-controller-overview">Обзор Action Controller</a>
</li><li><a href="/routing">Роутинг в Rails</a>
</li></ul></li><li><p><strong>Другие компоненты</strong></p><ul><li><a href="/active-support-core-extensions">Расширения ядра Active Support</a>
</li><li><a href="/action-mailer-basics">Основы Action Mailer</a>
</li><li><a href="/action-mailbox-basics">Основы Action Mailbox</a>
</li><li><a href="/action-text-overview">Обзор Action Text</a>
</li><li><a href="/active_job_basics">Основы Active Job</a>
</li><li><a href="/active_storage_overview">Обзор Active Storage</a>
</li><li><a href="/action-cable-overview">Обзор Action Cable</a>
</li></ul></li><li><p><strong>Копаем глубже</strong></p><ul><li><a href="/i18n">API интернационализации Rails (I18n)</a>
</li><li><a href="/testing">Тестирование приложений на Rails</a>
</li><li><a href="/security">Безопасность приложений на Rails</a>
</li><li><a href="/error-reporting">Отчет об ошибках в приложениях Rails</a>
</li><li><a href="/debugging-rails-applications">Отладка приложений на Rails</a>
</li></ul></li></ul><p>next_column</p><ul><li><p><strong>Копаем глубже</strong></p><ul><li><a href="/configuring">Конфигурирование приложений на Rails</a>
</li><li><a href="/command-line">Командная строка Rails</a>
</li><li><a href="/asset-pipeline">Asset Pipeline</a>
</li><li><a href="/working-with-javascript-in-rails">Работа с JavaScript в Rails</a>
</li><li><a href="/initialization">Процесс инициализации в Rails</a>
</li><li><a href="/autoloading-and-reloading-constants">Автозагрузка и перезагрузка констант</a>
</li><li><a href="/caching-with-rails">Кэширование с Rails: Обзор</a>
</li><li><a href="/active-support-instrumentation">Инструментарий Active Support</a>
</li><li><a href="/api-app">Использование Rails для API-приложений</a>
</li><li><a href="/active-record-postgresql">Active Record для PostgreSQL</a>
</li><li><a href="/active-record-multiple-databases">Несколько баз данных с Active Record</a>
</li><li><a href="/active-record-encryption">Шифрование Active Record</a>
</li></ul></li><li><p><strong>Расширяем Rails</strong></p><ul><li><a href="/plugins">Основы создания плагинов Rails</a>
</li><li><a href="/rails-on-rack">Rails on Rack</a>
</li><li><a href="/generators">Создание и настройка генераторов и шаблонов Rails</a>
</li><li><a href="/engines">Engine для начинающих</a>
</li><li><a href="/threading_and_code_execution">Треды и выполнение кода в Rails</a>
</li><li><a href="/rails-application-templates">Шаблоны приложения Rails</a>
</li></ul></li><li><p><strong>Вносим вклад в Ruby on Rails</strong></p><ul><li><a href="/contributing_to_ruby_on_rails">Вносим вклад в Ruby on Rails</a>
</li><li><a href="/api_documentation_guidelines">Рекомендации по документированию API</a>
</li><li><a href="/ruby_on_rails_guides_guidelines">Рекомендации для руководств по Ruby on Rails</a>
</li><li><a href="/development_dependencies_install">Установка зависимостей для разработки</a>
</li><li><a href="/maintenance-policy">Политика поддержки (версий)</a>
</li></ul></li><li><p><strong>Заметки о релизах</strong></p><ul><li><a href="/upgrading-ruby-on-rails">Апгрейд Ruby on Rails</a>
</li><li><a href="/7_2_release_notes">Версия 7.2 - ?</a>
</li><li><a href="/7_1_release_notes">Версия 7.1 - Октябрь 2023</a>
</li><li><a href="/7_0_release_notes">Версия 7.0 - Декабрь 2021</a>
</li><li><a href="/6_1_release_notes">Версия 6.1 - Декабрь 2020</a>
</li><li><a href="/6_0_release_notes">Версия 6.0 - Август 2019</a>
</li></ul></li></ul>
</div>
</li>
<li>
<a href="/search">Поиск</a>
</li>
<li>
<a target="blank" href="http://api.rusrails.ru">Ruby & Rails API</a>
</li>
</ul>
</div>
</div>
</div>
<div class="content-wrapper">
<div class="container-fluid">
<div class="row-fluid">
<div class="span3 pull-right">
<div class="well social">
<h4>Принимаем пожелания и пул-реквесты!</h4>
<iframe allowtransparency="true" frameborder="0" height="30" src="http://ghbtns.com/github-btn.html?user=rusrails&repo=rusrails&type=watch&count=true&size=large" width="180"></iframe>
</div>
<div class="well menu">
<ul class="nav nav-list">
<li>
<h4>
<a href="#chto-takoe-action-text">1. Что такое Action Text?</a>
</h4> </li>
<li>
<h4>
<a href="#ustanovka">2. Установка</a>
</h4> </li>
<li>
<h4>
<a href="#sozdanie-soderzhimogo-obogaschennogo-teksta">3. Создание содержимого обогащенного текста</a>
</h4> </li>
<li>
<h4>
<a href="#otobrazhenie-soderzhimogo-obogaschennogo-teksta">4. Отображение содержимого обогащенного текста</a>
</h4> </li>
<li>
<h4>
<a href="#nastroyka-redaktora-soderzhimogo-obogaschennogo-teksta-trix">5. Настройка редактора содержимого обогащенного текста (Trix)</a>
</h4> </li>
<li>
<h5>
<a href="#removing-or-adding-trix-styles">5.1. Удаление или добавление стилей Trix</a>
</h5> </li>
<li>
<h5>
<a href="#nastroyka-konteynera-redaktora">5.2. Настройка контейнера редактора</a>
</h5> </li>
<li>
<h5>
<a href="#nastroyka-html-dlya-vstroennyh-izobrazheniy-i-vlozheniy">5.3. Настройка HTML для встроенных изображений и вложений</a>
</h5> </li>
<li>
<h4>
<a href="#vlozheniya">6. Вложения</a>
</h4> </li>
<li>
<h5>
<a href="#active-storage">6.1. Active Storage</a>
</h5> </li>
<li>
<h5>
<a href="#signed-globalid">6.2. Signed GlobalID</a>
</h5> </li>
<li>
<h5>
<a href="#otobrazhenie-vlozheniya-action-text">6.3. Отображение вложения Action Text</a>
</h5> </li>
<li>
<h5>
<a href="#otobrazhenie-drugogo-partiala-dlya-action-text-attachment">6.4. Отображение другого партиала для action-text-attachment</a>
</h5> </li>
<li>
<h5>
<a href="#otobrazhenie-partiala-dlya-nesuschestvuyuschego-ekzemplyara-ili-otsutstvuyuschego-action-text-attachment">6.5. Отображение партиала для несуществующего экземпляра или отсутствующего action-text-attachment</a>
</h5> </li>
<li>
<h5>
<a href="#vlozhenie-cherez-api">6.6. Вложение через API</a>
</h5> </li>
<li>
<h4>
<a href="#prochee">7. Прочее</a>
</h4> </li>
<li>
<h5>
<a href="#izbeganie-n-1-zaprosa">7.1. Избегание N+1 запроса</a>
</h5> </li>
</ul>
</div>
<div class="well banner300 banner">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- sidebar rusrails -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:600px"
data-ad-client="ca-pub-7764391801669990"
data-ad-slot="6089520660"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
</div>
<div class="span9 content pull-left">
<div class="banner">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- top rusrails -->
<ins class="adsbygoogle"
style="display:inline-block;width:980px;height:120px"
data-ad-client="ca-pub-7764391801669990"
data-ad-slot="4891989065"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<h2 id='obzor-action-text' class='inside_page_header'> Обзор Action Text</h2><p>Это руководство предоставляет вам все, что нужно, чтобы начать обрабатывать содержимое обогащенного текста.</p><p>После прочтения этого руководства, вы узнаете:</p><ul><li>Что такое Action Text, как его установить и настроить.
</li><li>Как создать, отрендерить, стилизовать и доработать содержимое обогащенного текста.
</li><li>Как обработать вложения.
</li></ul>
<hr>
<h3 id='chto-takoe-action-text' class='inside_page_header'><a href="#chto-takoe-action-text">1.</a> Что такое Action Text?</h3><p>Action Text упрощает обработку и отображение содержимого обогащенного текста. Под содержимым обогащенного текста понимается текст, который включает элементы форматирования, такие как жирный шрифт, курсив, цвета и гиперссылки, обеспечивая визуально улучшенное и структурированное представление по сравнению с простым текстом. Он позволяет нам создавать содержимое обогащенного текста, сохранять его в таблице, а затем прикреплять к любым моделям.</p><p>Action Text включает в себя редактор <a href="https://en.wikipedia.org/wiki/WYSIWYG">WYSIWYG</a> под названием Trix, который используется в веб-приложениях для предоставления пользователям удобного интерфейса для создания и редактирования содержимого обогащенного текста. Он позволяет форматировать текст, добавлять ссылки или цитаты, вставлять изображения и многое другое. Пример работы редактора Trix можно посмотреть <a href="https://trix-editor.org/">здесь</a>.</p><p>Содержимое обогащенного текста, созданное редактором Trix, сохраняется в отдельной модели RichText, которую можно связать с любой существующей моделью Active Record в приложении. Кроме того, любые встроенные изображения (или другие вложения) могут быть автоматически сохранены с помощью Active Storage (которое добавляется как зависимость) и связаны с этой моделью RichText. Когда приходит время отображать содержимое, Action Text обрабатывает его, сначала очищая, чтобы его можно было безопасно встроить непосредственно в HTML страницы.</p><div class="info"><p>Большинство редакторов WYSIWYG представляют собой обертки вокруг API HTML <code>contenteditable</code> и <code>execCommand</code>. Эти API были разработаны Microsoft для поддержки редактирования веб-страниц в реальном времени в Internet Explorer 5.5. Впоследствии они были случайно обратно разработаны и скопированы другими браузерами. Следовательно, эти API никогда не были полностью специфицированы или документированы, а поскольку HTML редакторы WYSIWYG имеют огромный объем возможностей, в реализации для каждого браузера есть свой набор ошибок и странностей. Таким образом, JavaScript-разработчики часто оставлены наедине разбираться с этими неудобствами.<br><br> Trix обходит эти несоответствия, рассматривая <code>contenteditable</code> как устройство ввода-вывода: когда в редактор поступает ввод, Trix преобразует его в операцию редактирования внутренней модели документа, а затем повторно отображает этот документ в редакторе. Это дает Trix полный контроль над тем, что происходит после каждого нажатия клавиши, и позволяет избежать использования <code>execCommand</code> и связанных с ним несоответствий.</p></div><h3 id='ustanovka' class='inside_page_header'><a href="#ustanovka">2.</a> Установка</h3><p>Чтобы установить Action Text и начать работать с содержимым обогащенного текста, запустите:</p><div class="code_container">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>action_text:install
</code></pre>
</div>
<p>Это выполнит следующие действия:</p><ul><li>Установит JavaScript-пакеты для <code>trix</code> и <code>@rails/actiontext</code> и добавит их в <code>application.js</code>.
</li><li>Добавит gem <code>image_processing</code> для анализа и преобразования встроенных изображений и других вложений с помощью Active Storage. За подробностями обратитесь к руководству <a href="/active_storage_overview">Обзор Active Storage</a>.
</li><li>Создаст миграции для создания следующих таблиц, хранящих содержимое обогащенного текста и вложения: <code>action_text_rich_texts</code>, <code>active_storage_blobs</code> <code>active_storage_attachments</code>, <code>active_storage_variant_records</code>.
</li><li>Создаст <code>actiontext.css</code> и импортирует его в <code>application.css</code>. Таблица стилей Trix также будет включена в файл <code>application.css</code>.
</li><li>Добавит стандартные партиалы <code>_content.html</code> и <code>_blob.html</code> для отображения содержимого Action Text и вложений Active Storage (также называемых blob) соответственно.
</li></ul><p>После этого, запуск миграций добавит в ваше приложение новые таблицы <code>action_text_*</code> и <code>active_storage_*</code>.</p><div class="code_container">
<pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>db:migrate
</code></pre>
</div>
<p>Когда установка Action Text создает таблицу <code>action_text_rich_texts</code>, она использует полиморфную связь, позволяющую нескольким моделям добавлять атрибуты обогащенного текста. Это реализуется через столбцы <code>record_type</code> и <code>record_id</code>, которые хранят соответственно имя класса модели и ID записи.</p><div class="info"><p>С использованием полиморфных связей модель может принадлежать более чем одной модели на единственной связи. Подробности смотрите в <a href="/active-record-associations#polymorphic-associations">руководстве по связям Active Record</a>.</p></div><p>Следовательно, если ваши модели, с содержимым Action Text, используют значения UUID в качестве идентификаторов, то все модели, использующие атрибуты Action Text, должны использовать значения UUID для своих уникальных идентификаторов. Сгенерированную миграцию для Action Text также необходимо обновить, указав <code>type: :uuid</code> в строчке ссылки на запись.</p><div class="code_container">
<pre><code class="highlight ruby"><span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:record</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">polymorphic: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">index: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">type: :uuid</span>
</code></pre>
</div>
<h3 id='sozdanie-soderzhimogo-obogaschennogo-teksta' class='inside_page_header'><a href="#sozdanie-soderzhimogo-obogaschennogo-teksta">3.</a> Создание содержимого обогащенного текста</h3><p>В этом разделе мы рассмотрим некоторые конфигурации, необходимые для создания обогащенного текста.</p><p>Запись RichText хранит содержимое, созданное редактором Trix, в сериализованном атрибуте <code>body</code>. Она также содержит все ссылки на встроенные файлы, которые хранятся с помощью Active Storage. Эта запись затем связывается с моделью Active Record, в которой желаете иметь содержимое обогащенного текста. Связь устанавливается путем размещения метода класса <code>has_rich_text</code> в модели, к которой вы хотите добавить обогащенный текст.</p><div class="code_container">
<pre><code class="highlight ruby"><span class="c1"># app/models/article.rb</span>
<span class="k">class</span> <span class="nc">Article</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">has_rich_text</span> <span class="ss">:content</span>
<span class="k">end</span>
</code></pre>
</div>
<div class="note"><p>Вам не нужно добавлять столбец <code>content</code> в таблицу Article. <code>has_rich_text</code> связывает content с таблицей <code>action_text_rich_texts</code>, которая уже была создана, и устанавливает связь с вашей моделью. Вы также можете выбрать именем атрибута что-то иное, чем <code>content</code>.</p></div><p>После добавления метода класса <code>has_rich_text</code> в модель можно обновить вью, чтобы использовать редактор обогащенного текста (Trix) для этого поля. Для этого используйте <a href="https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-rich_text_area"><code>rich_text_area</code></a> для поля формы.</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/articles/_form.html.erb %></span>
<span class="cp"><%=</span> <span class="n">form_with</span> <span class="ss">model: </span><span class="n">article</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:content</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">rich_text_area</span> <span class="ss">:content</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre>
</div>
<p>Это отобразит редактор Trix, который предоставляет функции для создания и обновления вашего обогащенного текста. Позже мы подробно рассмотрим, <a href="#removing-or-adding-trix-styles">как обновить стили для редактора</a>.</p><p>Наконец, чтобы гарантировать возможность принимать обновления от редактора, вам необходимо разрешить использование ссылаемого атрибута в качестве параметра в соответствующем контроллере:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ArticlesController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">create</span>
<span class="n">article</span> <span class="o">=</span> <span class="no">Article</span><span class="p">.</span><span class="nf">create!</span> <span class="n">params</span><span class="p">.</span><span class="nf">require</span><span class="p">(</span><span class="ss">:article</span><span class="p">).</span><span class="nf">permit</span><span class="p">(</span><span class="ss">:title</span><span class="p">,</span> <span class="ss">:content</span><span class="p">)</span>
<span class="n">redirect_to</span> <span class="n">article</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</div>
<p>Если вдруг вам нужно переименовать классы, использующие <code>has_rich_text</code>, вам также необходимо обновить столбец полиморфного типа <code>record_type</code> в таблице <code>action_text_rich_texts</code> для соответствующих строк.</p><p>Поскольку Action Text зависит от полиморфных связей, которые, в свою очередь, подразумевают хранение названий классов в базе данных, крайне важно синхронизировать эти данные с названиями классов, используемыми в вашем Ruby-коде. Эта синхронизация необходима для обеспечения соответствия между хранимыми данными и ссылками на классы в вашем коде.</p><h3 id='otobrazhenie-soderzhimogo-obogaschennogo-teksta' class='inside_page_header'><a href="#otobrazhenie-soderzhimogo-obogaschennogo-teksta">4.</a> Отображение содержимого обогащенного текста</h3><p>Экземпляры <code>ActionText::RichText</code> можно напрямую встраивать на страницу, поскольку их содержимое уже очищено для безопасного отображения. Вы можете отобразить содержимое следующим образом:</p><div class="code_container">
<pre><code class="highlight erb"><span class="cp"><%=</span> <span class="vi">@article</span><span class="p">.</span><span class="nf">content</span> <span class="cp">%></span>
</code></pre>
</div>
<p><code>ActionText::RichText#to_s</code> безопасно преобразует RichText в HTML-строку. С другой стороны, <code>ActionText::RichText#to_plain_text</code> возвращает строку, не являющуюся безопасной для HTML и которую не следует отображать в браузерах. Подробнее о процессе очистки Action Text можно узнать в <a href="https://api.rubyonrails.org/classes/ActionText/RichText.html">документации</a> для класса ActionText::RichText.</p><div class="note"><p>Если в поле <code>content</code> есть прикрепленный ресурс, он может отображаться неправильно, если у вас не установлены необходимые <a href="/active_storage_overview#requirements">зависимости для Active Storage</a>.</p></div><h3 id='nastroyka-redaktora-soderzhimogo-obogaschennogo-teksta-trix' class='inside_page_header'><a href="#nastroyka-redaktora-soderzhimogo-obogaschennogo-teksta-trix">5.</a> Настройка редактора содержимого обогащенного текста (Trix)</h3><p>Возможно, вам захочется изменить внешний вид редактора, чтобы он соответствовал вашим стилистическим требованиям, в этом разделе рассказывается, как это сделать.</p><h4 id='removing-or-adding-trix-styles' class='inside_page_header'><a href="#removing-or-adding-trix-styles">5.1.</a> Удаление или добавление стилей Trix</h4><p>По умолчанию Action Text отобразит содержимое обогащенного текста внутри элемента с классом <code>.trix-content</code>. Это установлено в <code>app/views/layouts/action_text/contents/_content.html.erb</code>. Элементы с этим классом затем стилизуются с помощью таблицы стилей.</p><p>Если вы хотите изменить любые стили Trix, вы можете добавить свои собственные стили в файл <code>app/assets/stylesheets/actiontext.css</code>.</p><p>Однако, если вы хотите использовать свои собственные стили или стороннюю библиотеку вместо стандартных стилей trix, вы можете отключить trix в директивах препроцессора в файле <code>app/assets/stylesheets/actiontext.css</code>, удалив следующее:</p><div class="code_container">
<pre><code class="highlight css"><span class="o">=</span> <span class="nt">require</span> <span class="nt">trix</span>
</code></pre>
</div>
<h4 id='nastroyka-konteynera-redaktora' class='inside_page_header'><a href="#nastroyka-konteynera-redaktora">5.2.</a> Настройка контейнера редактора</h4><p>Чтобы настроить элемент HTML-контейнера, отображаемый вокруг содержимого обогащенного текста, отредактируйте файл макета <code>app/views/layouts/action_text/contents/_content.html.erb</code>, созданный установщиком:</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/layouts/action_text/contents/_content.html.erb %></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"trix-content"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="k">yield</span> <span class="cp">%></span>
<span class="nt"></div></span>
</code></pre>
</div>
<h4 id='nastroyka-html-dlya-vstroennyh-izobrazheniy-i-vlozheniy' class='inside_page_header'><a href="#nastroyka-html-dlya-vstroennyh-izobrazheniy-i-vlozheniy">5.3.</a> Настройка HTML для встроенных изображений и вложений</h4><p>Чтобы изменить HTML, отображаемый для встроенных изображений и других вложений (известных как бинарные объекты), отредактируйте шаблон <code>app/views/active_storage/blobs/_blob.html.erb</code>, созданный установщиком:</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/active_storage/blobs/_blob.html.erb %></span>
<span class="nt"><figure</span> <span class="na">class=</span><span class="s">"attachment attachment--</span><span class="cp"><%=</span> <span class="n">blob</span><span class="p">.</span><span class="nf">representable?</span> <span class="p">?</span> <span class="s2">"preview"</span> <span class="p">:</span> <span class="s2">"file"</span> <span class="cp">%></span><span class="s"> attachment--</span><span class="cp"><%=</span> <span class="n">blob</span><span class="p">.</span><span class="nf">filename</span><span class="p">.</span><span class="nf">extension</span> <span class="cp">%></span><span class="s">"</span><span class="nt">></span>
<span class="cp"><%</span> <span class="k">if</span> <span class="n">blob</span><span class="p">.</span><span class="nf">representable?</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">image_tag</span> <span class="n">blob</span><span class="p">.</span><span class="nf">representation</span><span class="p">(</span><span class="ss">resize_to_limit: </span><span class="n">local_assigns</span><span class="p">[</span><span class="ss">:in_gallery</span><span class="p">]</span> <span class="p">?</span> <span class="p">[</span> <span class="mi">800</span><span class="p">,</span> <span class="mi">600</span> <span class="p">]</span> <span class="p">:</span> <span class="p">[</span> <span class="mi">1024</span><span class="p">,</span> <span class="mi">768</span> <span class="p">])</span> <span class="cp">%></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"><figcaption</span> <span class="na">class=</span><span class="s">"attachment__caption"</span><span class="nt">></span>
<span class="cp"><%</span> <span class="k">if</span> <span class="n">caption</span> <span class="o">=</span> <span class="n">blob</span><span class="p">.</span><span class="nf">try</span><span class="p">(</span><span class="ss">:caption</span><span class="p">)</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">caption</span> <span class="cp">%></span>
<span class="cp"><%</span> <span class="k">else</span> <span class="cp">%></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"attachment__name"</span><span class="nt">></span><span class="cp"><%=</span> <span class="n">blob</span><span class="p">.</span><span class="nf">filename</span> <span class="cp">%></span><span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"attachment__size"</span><span class="nt">></span><span class="cp"><%=</span> <span class="n">number_to_human_size</span> <span class="n">blob</span><span class="p">.</span><span class="nf">byte_size</span> <span class="cp">%></span><span class="nt"></span></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"></figcaption></span>
<span class="nt"></figure></span>
</code></pre>
</div>
<h3 id='vlozheniya' class='inside_page_header'><a href="#vlozheniya">6.</a> Вложения</h3><p>В настоящее время Action Text поддерживает вложения, загруженные через Active Storage, а также вложения, связанные с Signed GlobalID.</p><h4 id='active-storage' class='inside_page_header'><a href="#active-storage">6.1.</a> Active Storage</h4><p>Когда вы загружаете изображение через редактор обогащенного текста, он использует Action Text, который, в свою очередь, использует Active Storage. Однако, Active Storage имеет <a href="/active_storage_overview#requirements">некоторые зависимости</a>, которые не предоставляются Rails. Чтобы использовать встроенные функции предварительного просмотра, вам необходимо установить эти библиотеки.</p><p>Некоторые, но не все библиотеки обязательны, их необходимость зависит от того, какие типы файлов вы планируете загружать в редактор. Одной из распространенных ошибок, с которой сталкиваются пользователи при работе с Action Text и Active Storage, является неправильное отображение изображений в редакторе. Обычно это происходит из-за отсутствия зависимости <code>libvips</code>.</p><h4 id='signed-globalid' class='inside_page_header'><a href="#signed-globalid">6.2.</a> Signed GlobalID</h4><p>В дополнение к вложениям, загруженным с помощью Active Storage, Action Text также может встроить все, что может быть найдено по <a href="https://github.com/rails/globalid#signed-global-ids">Signed GlobalID</a>.</p><p>Global ID - это универсальный URI для всего приложения, который уникально идентифицирует экземпляр модели: <code>gid://YourApp/Some::Model/id</code>. Это полезно, когда вам нужен единый идентификатор для ссылки на объекты разных классов.</p><p>При использовании этого метода Action Text требует, чтобы у вложений был подписанный глобальный идентификатор (sgid). По умолчанию, все модели Active Record в приложении Rails включают в себя поддержку <code>GlobalID::Identification</code>, поэтому их можно определить по подписанному глобальному идентификатору, что делает их совместимыми с <code>ActionText::Attachable</code>.</p><p>Action Text ссылается на HTML, который вы вставляете при сохранении, чтобы он мог позже перерисовать его с актуальным содержимым. Это позволяет ссылаться на модели и всегда отображать актуальное содержимое, даже если эти записи изменяются.</p><p>Action Text загрузит модель по глобальному идентификатору и затем отобразит ее с использованием пути по умолчанию, когда вы отрисовываете содержимое.</p><p>Пример вложения Action Text:</p><div class="code_container">
<pre><code class="highlight html"><span class="nt"><action-text-attachment</span> <span class="na">sgid=</span><span class="s">"BAh7CEkiCG…"</span><span class="nt">></action-text-attachment></span>
</code></pre>
</div>
<p>Action Text отрисовывает вложенные элементы <code><action-text-attachment></code>, преобразовывая их атрибут sgid элемента в экземпляр. Будучи найденным, этот экземпляр передается в хелпер отрисовки. В результате HTML вкладывается как потомок элемента <code><action-text-attachment></code>.</p><p>Для отображения в качестве вложения в элементе <code><action-text-attachment></code> Action Text, мы должны включить модуль <code>ActionText::Attachable</code>, который реализует <code>#to_sgid(**options)</code> (доступный через <code>GlobalID::Identification</code>).</p><p>Вы также можете (опционально) объявить <code>#to_attachable_partial_path</code> для отображения пользовательского пути к партиалу и <code>#to_missing_attachable_partial_path</code> для обработки отсутствующих записей.</p><p>Вот пример:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">Person</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="kp">include</span> <span class="no">ActionText</span><span class="o">::</span><span class="no">Attachable</span>
<span class="k">end</span>
<span class="n">person</span> <span class="o">=</span> <span class="no">Person</span><span class="p">.</span><span class="nf">create!</span> <span class="ss">name: </span><span class="s2">"Javan"</span>
<span class="n">html</span> <span class="o">=</span> <span class="sx">%Q(<action-text-attachment sgid="</span><span class="si">#{</span><span class="n">person</span><span class="p">.</span><span class="nf">attachable_sgid</span><span class="si">}</span><span class="sx">"></action-text-attachment>)</span>
<span class="n">content</span> <span class="o">=</span> <span class="no">ActionText</span><span class="o">::</span><span class="no">Content</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">html</span><span class="p">)</span>
<span class="n">content</span><span class="p">.</span><span class="nf">attachables</span> <span class="c1"># => [person]</span>
</code></pre>
</div>
<h4 id='otobrazhenie-vlozheniya-action-text' class='inside_page_header'><a href="#otobrazhenie-vlozheniya-action-text">6.3.</a> Отображение вложения Action Text</h4><p>Стандартный способ отображения элемента <code><action-text-attachment></code> осуществляется через партиал пути по умолчанию.</p><p>Для наглядности рассмотрим модель User:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="c1"># app/models/user.rb</span>
<span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">has_one_attached</span> <span class="ss">:avatar</span>
<span class="k">end</span>
<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">user</span><span class="p">.</span><span class="nf">to_global_id</span><span class="p">.</span><span class="nf">to_s</span> <span class="c1">#=> gid://MyRailsApp/User/1</span>
<span class="n">user</span><span class="p">.</span><span class="nf">to_signed_global_id</span><span class="p">.</span><span class="nf">to_s</span> <span class="c1">#=> BAh7CEkiCG…</span>
</code></pre>
</div>
<div class="note"><p>Мы можем использовать <code>GlobalID::Identification</code> для любой модели с методом класса <code>.find(id)</code>. Поддержка автоматически включена в Active Record.</p></div><p>Приведённый выше код вернет наш идентификатор для уникальной идентификации экземпляра модели.</p><p>Затем, рассмотрим некоторое содержимое обогащенного текста, в которое вложен элемент <code><action-text-attachment></code>, ссылающийся на подписанный GlobalID экземпляра User:</p><div class="code_container">
<pre><code class="highlight html"><span class="nt"><p></span>Hello, <span class="nt"><action-text-attachment</span> <span class="na">sgid=</span><span class="s">"BAh7CEkiCG…"</span><span class="nt">></action-text-attachment></span>.<span class="nt"></p></span>
</code></pre>
</div>
<p>Action Text использует строку "BAh7CEkiCG…", чтобы найти экземпляр <code>User</code>. Затем он отрисовывает его с использованием пути партиала по умолчанию для отрисовки содержимого.</p><p>В данном случае пути партиала по умолчанию - партиал <code>users/user</code>.</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/users/_user.html.erb %></span>
<span class="nt"><span></span><span class="cp"><%=</span> <span class="n">image_tag</span> <span class="n">user</span><span class="p">.</span><span class="nf">avatar</span> <span class="cp">%></span> <span class="cp"><%=</span> <span class="n">user</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span><span class="nt"></span></span>
</code></pre>
</div>
<p>Следовательно, результирующий HTML, отрисованный Action Text, будет выглядеть наподобие:</p><div class="code_container">
<pre><code class="highlight html"><span class="nt"><p></span>Hello, <span class="nt"><action-text-attachment</span> <span class="na">sgid=</span><span class="s">"BAh7CEkiCG…"</span><span class="nt">><span><img</span> <span class="na">src=</span><span class="s">"..."</span><span class="nt">></span> Jane Doe<span class="nt"></span></action-text-attachment></span>.<span class="nt"></p></span>
</code></pre>
</div>
<h4 id='otobrazhenie-drugogo-partiala-dlya-action-text-attachment' class='inside_page_header'><a href="#otobrazhenie-drugogo-partiala-dlya-action-text-attachment">6.4.</a> Отображение другого партиала для action-text-attachment</h4><p>Чтобы отобразить другой партиал для вложения, определите <code>User#to_attachable_partial_path</code>:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="k">def</span> <span class="nf">to_attachable_partial_path</span>
<span class="s2">"users/attachable"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</div>
<p>Затем объявите этот партиал. Экземпляр User будет доступен как локальная для партиала переменная user:</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/users/_attachable.html.erb %></span>
<span class="nt"><span></span><span class="cp"><%=</span> <span class="n">image_tag</span> <span class="n">user</span><span class="p">.</span><span class="nf">avatar</span> <span class="cp">%></span> <span class="cp"><%=</span> <span class="n">user</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span><span class="nt"></span></span>
</code></pre>
</div>
<h4 id='otobrazhenie-partiala-dlya-nesuschestvuyuschego-ekzemplyara-ili-otsutstvuyuschego-action-text-attachment' class='inside_page_header'><a href="#otobrazhenie-partiala-dlya-nesuschestvuyuschego-ekzemplyara-ili-otsutstvuyuschego-action-text-attachment">6.5.</a> Отображение партиала для несуществующего экземпляра или отсутствующего action-text-attachment</h4><p>Если Action Text не может найти экземпляр User (например, если запись была удалена), будет отображен резервный партиал.</p><p>Для отрисовки другого партиала для отсутствующих вложений, определите метод на уровне класса <code>to_missing_attachable_partial_path</code>:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">to_missing_attachable_partial_path</span>
<span class="s2">"users/missing_attachable"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</div>
<p>Затем объявите этот партиал.</p><div class="code_container">
<pre><code class="highlight erb"><span class="c"><%# app/views/users/missing_attachable.html.erb %></span>
<span class="nt"><span></span>Deleted user<span class="nt"></span></span>
</code></pre>
</div>
<h4 id='vlozhenie-cherez-api' class='inside_page_header'><a href="#vlozhenie-cherez-api">6.6.</a> Вложение через API</h4><p>Если ваша архитектура не использует традиционную схему с серверным отображением Rails,то, возможно, вам понадобится отдельная точка доступа API (например, с использованием JSON) на стороне сервера для загрузки файлов. Эта точка доступа должна создавать объект <code>ActiveStorage::Blob</code> и возвращать его <code>attachable_sgid</code>.</p><div class="code_container">
<pre><code class="highlight json"><span class="p">{</span><span class="w">
</span><span class="nl">"attachable_sgid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"BAh7CEkiCG…"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
</div>
<p>Затем полученный <code>attachable_sgid</code> вы можете вставить в ваше содержимое обогащенного текста в коде фронтенда с помощью тега <code><action-text-attachment></code>:</p><div class="code_container">
<pre><code class="highlight html"><span class="nt"><action-text-attachment</span> <span class="na">sgid=</span><span class="s">"BAh7CEkiCG…"</span><span class="nt">></action-text-attachment></span>
</code></pre>
</div>
<h3 id='prochee' class='inside_page_header'><a href="#prochee">7.</a> Прочее</h3><h4 id='izbeganie-n-1-zaprosa' class='inside_page_header'><a href="#izbeganie-n-1-zaprosa">7.1.</a> Избегание N+1 запроса</h4><p>Если хотите предварительно загрузить зависимую модель <code>ActionText::RichText</code>, если допустить, что поле обогащенного текста названо <code>content</code>, можно использовать именованный скоуп:</p><div class="code_container">
<pre><code class="highlight ruby"><span class="no">Article</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">with_rich_text_content</span> <span class="c1"># Загружает тело без вложений.</span>
<span class="no">Article</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">with_rich_text_content_and_embeds</span> <span class="c1"># Загружает тело и вложения.</span>
</code></pre>
</div>
<div class="banner">
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- bottom rusrails -->
<ins class="adsbygoogle"
style="display:inline-block;width:580px;height:400px"
data-ad-client="ca-pub-7764391801669990"
data-ad-slot="7566253867"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12" id="footer">
<p>
<a target="blank" href="https://github.com/rusrails/rusrails"><img src="/assets/github-7cc23602a5ac2465f14c19492358a5a67dc24636761cc723e4d621cea0c09225.png" /></a>
</p>
<p>
<a href="https://creativecommons.org/licenses/by-sa/4.0/">Лицензия CC BY-SA 4.0</a>
"Rails", "Ruby on Rails" и логотип Rails - торговые марки DHH
<!-- Yandex.Metrika counter -->
<script>
(function (d, w, c) {
(w[c] = w[c] || []).push(function() {
try {
w.yaCounter1006929 = new Ya.Metrika({id:1006929,
webvisor:true,
clickmap:true,
trackLinks:true,
accurateTrackBounce:true});
} catch(e) { }
});
var n = d.getElementsByTagName("script")[0],
s = d.createElement("script"),
f = function () { n.parentNode.insertBefore(s, n); };
s.type = "text/javascript";
s.async = true;
s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js";
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else { f(); }
})(document, window, "yandex_metrika_callbacks");
</script>
<noscript>
<div>
<img style="position:absolute; left:-9999px;" alt="" src="//mc.yandex.ru/watch/1006929" />
</div>
</noscript>
<!-- /Yandex.Metrika counter -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-64955373-1', 'auto');
ga('send', 'pageview');
var trackOutboundLink = function(url) {
ga('send', 'event', 'outbound', 'click', url, {
'transport': 'beacon',
'hitCallback': function(){ }
});
}
</script>
</p>
</div>
</div>
</div>
</div>
<div class="to_top" style="display: block">
<div class="to_top_panel"></div>
</div>
<script src="/assets/application-48ac5c5be8858f5558a99606c2d341f9fee482f22db6deee5def03837c505584.js"></script>
</body>
</html>