---
title: "How to Embed Youtube videos with ActionText? TLDR"
author: "Yaroslav Shmarov"
date: "2020-11-23"
canonical_url: "https://blog.superails.com/action-text-embed-youtube"
markdown_url: "https://blog.superails.com/action-text-embed-youtube.md"
description: "Original Youtube video where it is introduced by Chris Oliver{:target=\"blank\"} app/views/youtubes/_thumbnail.html.erb &lt; div &gt; &lt;"
tags: ["ruby-on-rails","actiontext","youtube","embed","tldr"]
license: "GNU AGPL v3. Credit Yaroslav Shmarov and link the canonical URL."
---

# How to Embed Youtube videos with ActionText? TLDR

# Final result:
![embed youtube actiontext](https://blog.superails.com/assets/2020-11-16-action-text-embed-youtube/embed youtube actiontext.gif)

[Original Youtube video where it is introduced by Chris Oliver](https://www.youtube.com/watch?v=2iGBuLQ3S0c){:target="blank"}

app/views/youtubes/_thumbnail.html.erb
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">&lt;</span><span class="n">div</span><span class="o">&gt;</span>
  <span class="o">&lt;</span><span class="sx">%= image_tag youtube.thumbnail_url, style: "max-width:400px" %&gt;
&lt;/div&gt;</span></code></pre></figure> 

app/views/youtubes/_youtube.html.erb
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">&lt;</span><span class="n">div</span><span class="o">&gt;</span>
  <span class="o">&lt;</span><span class="n">iframe</span> <span class="nb">id</span><span class="o">=</span><span class="s2">"ytplayer"</span> <span class="n">type</span><span class="o">=</span><span class="s2">"text/html"</span> <span class="n">width</span><span class="o">=</span><span class="s2">"640"</span> <span class="n">height</span><span class="o">=</span><span class="s2">"360"</span> <span class="n">src</span><span class="o">=</span><span class="s2">"https://www.youtube.com/embed/&lt;%= youtube.id %&gt;"</span> <span class="n">frameborder</span><span class="o">=</span><span class="s2">"0"</span><span class="o">&gt;&lt;</span><span class="sr">/iframe&gt;
&lt;/</span><span class="n">div</span><span class="o">&gt;</span></code></pre></figure> 

packs/application.js
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">import</span> <span class="s2">"youtube"</span></code></pre></figure> 


application.rb 
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby">    <span class="n">config</span><span class="p">.</span><span class="nf">to_prepare</span> <span class="k">do</span>
      <span class="no">ActionText</span><span class="o">::</span><span class="no">ContentHelper</span><span class="p">.</span><span class="nf">allowed_tags</span> <span class="o">&lt;&lt;</span> <span class="s2">"iframe"</span>
    <span class="k">end</span></code></pre></figure> 

routes.rb
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby">  <span class="n">resources</span> <span class="ss">:youtube</span><span class="p">,</span> <span class="ss">only: :show</span></code></pre></figure> 

models/youtube.rb
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Youtube</span>
  <span class="kp">include</span> <span class="no">ActiveModel</span><span class="o">::</span><span class="no">Model</span>
  <span class="kp">include</span> <span class="no">ActiveModel</span><span class="o">::</span><span class="no">Attributes</span>
  <span class="kp">include</span> <span class="no">GlobalID</span><span class="o">::</span><span class="no">Identification</span>
  <span class="kp">include</span> <span class="no">ActionText</span><span class="o">::</span><span class="no">Attachable</span>

  <span class="n">attribute</span> <span class="ss">:id</span>

  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">find</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
    <span class="n">new</span><span class="p">(</span><span class="ss">id: </span><span class="nb">id</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">thumbnail_url</span>
    <span class="s2">"http://i3.ytimg.com/vi/</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">/maxresdefault.jpg"</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">to_trix_content_attachment_partial_path</span>
    <span class="s2">"youtubes/thumbnail"</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure> 

controllers/youtube_controller.rb
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">YoutubeController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
  <span class="k">def</span> <span class="nf">show</span>
    <span class="vi">@youtube</span> <span class="o">=</span> <span class="no">Youtube</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">id: </span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
    <span class="n">render</span> <span class="ss">json: </span><span class="p">{</span>
      <span class="ss">sgid: </span><span class="vi">@youtube</span><span class="p">.</span><span class="nf">attachable_sgid</span><span class="p">,</span>
      <span class="ss">content: </span><span class="n">render_to_string</span><span class="p">(</span><span class="ss">partial: </span><span class="s2">"youtubes/thumbnail"</span><span class="p">,</span> <span class="ss">locals: </span><span class="p">{</span> <span class="ss">youtube: </span><span class="vi">@youtube</span> <span class="p">},</span> <span class="ss">formats: </span><span class="p">[</span><span class="ss">:html</span><span class="p">])</span>
    <span class="p">}</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure> 
  
javascript/youtube.js
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">import</span> <span class="no">Trix</span> <span class="n">from</span> <span class="s2">"trix"</span>
<span class="n">import</span> <span class="no">Rails</span> <span class="n">from</span> <span class="s2">"@rails/ujs"</span>

<span class="n">let</span> <span class="n">lang</span> <span class="o">=</span> <span class="no">Trix</span><span class="p">.</span><span class="nf">config</span><span class="p">.</span><span class="nf">lang</span><span class="p">;</span>
<span class="no">Trix</span><span class="p">.</span><span class="nf">config</span><span class="p">.</span><span class="nf">toolbar</span> <span class="o">=</span> <span class="p">{</span>
  <span class="ss">getDefaultHTML: </span><span class="n">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="sb">`
    &lt;div class="trix-button-row"&gt;
      &lt;span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools"&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1"&gt;${lang.bold}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1"&gt;${lang.italic}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1"&gt;${lang.strike}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1"&gt;${lang.link}&lt;/button&gt;
      &lt;/span&gt;
      &lt;span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools"&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-heading-1" data-trix-attribute="heading1" title="${lang.heading1}" tabindex="-1"&gt;${lang.heading1}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-quote" data-trix-attribute="quote" title="${lang.quote}" tabindex="-1"&gt;${lang.quote}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-code" data-trix-attribute="code" title="${lang.code}" tabindex="-1"&gt;${lang.code}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${lang.bullets}" tabindex="-1"&gt;${lang.bullets}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${lang.numbers}" tabindex="-1"&gt;${lang.numbers}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-decrease-nesting-level" data-trix-action="decreaseNestingLevel" title="${lang.outdent}" tabindex="-1"&gt;${lang.outdent}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-increase-nesting-level" data-trix-action="increaseNestingLevel" title="${lang.indent}" tabindex="-1"&gt;${lang.indent}&lt;/button&gt;
      &lt;/span&gt;
      &lt;span class="trix-button-group trix-button-group--file-tools" data-trix-button-group="file-tools"&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-attach" data-trix-action="attachFiles" title="${lang.attachFiles}" tabindex="-1"&gt;${lang.attachFiles}&lt;/button&gt;
      &lt;/span&gt;
      &lt;span class="trix-button-group-spacer"&gt;&lt;/span&gt;
      &lt;span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools"&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${lang.undo}" tabindex="-1"&gt;${lang.undo}&lt;/button&gt;
        &lt;button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${lang.redo}" tabindex="-1"&gt;${lang.redo}&lt;/button&gt;
      &lt;/span&gt;
    &lt;/div&gt;
    &lt;div class="trix-dialogs" data-trix-dialogs&gt;
      &lt;div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href"&gt;
        &lt;div class="trix-dialog__link-fields"&gt;
          &lt;input type="url" name="href" class="trix-input trix-input--dialog" placeholder="${lang.urlPlaceholder}" aria-label="${lang.url}" required data-trix-input&gt;
          &lt;div class="flex"&gt;
            &lt;input type="button" class="btn btn-secondary btn-small mr-1" value="${lang.link}" data-trix-method="setAttribute"&gt;
            &lt;input type="button" class="btn btn-tertiary outline btn-small" value="${lang.unlink}" data-trix-method="removeAttribute"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div data-behavior="embed_container"&gt;
          &lt;div class="link_to_embed link_to_embed--new"&gt;
            Would you like to embed media from this site?
            &lt;input class="btn btn-tertiary outline btn-small ml-3" type="button" data-behavior="embed_url" value="Yes, embed it"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="k">class</span> <span class="nc">EmbedController</span> <span class="p">{</span>
  <span class="n">constructor</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">pattern</span> <span class="o">=</span> <span class="sr">/^https:\/\/([^\.]+\.)?youtube\.com\/watch\?v=(.*)/</span>

    <span class="n">this</span><span class="p">.</span><span class="nf">element</span> <span class="o">=</span> <span class="n">element</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">editor</span> <span class="o">=</span> <span class="n">element</span><span class="p">.</span><span class="nf">editor</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">toolbar</span> <span class="o">=</span> <span class="n">element</span><span class="p">.</span><span class="nf">toolbarElement</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">hrefElement</span> <span class="o">=</span> <span class="n">this</span><span class="p">.</span><span class="nf">toolbar</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="s2">"[data-trix-input][name='href']"</span><span class="p">)</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">embedContainerElement</span> <span class="o">=</span> <span class="n">this</span><span class="p">.</span><span class="nf">toolbar</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="s2">"[data-behavior='embed_container']"</span><span class="p">)</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">embedElement</span> <span class="o">=</span> <span class="n">this</span><span class="p">.</span><span class="nf">toolbar</span><span class="p">.</span><span class="nf">querySelector</span><span class="p">(</span><span class="s2">"[data-behavior='embed_url']"</span><span class="p">)</span>

    <span class="n">this</span><span class="p">.</span><span class="nf">reset</span><span class="p">()</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">installEventHandlers</span><span class="p">()</span>
  <span class="p">}</span>

  <span class="n">installEventHandlers</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">hrefElement</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="s2">"input"</span><span class="p">,</span> <span class="n">this</span><span class="p">.</span><span class="nf">didInput</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="n">this</span><span class="p">))</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">hrefElement</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="s2">"focusin"</span><span class="p">,</span> <span class="n">this</span><span class="p">.</span><span class="nf">didInput</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="n">this</span><span class="p">))</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">embedElement</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="s2">"click"</span><span class="p">,</span> <span class="n">this</span><span class="p">.</span><span class="nf">embed</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="n">this</span><span class="p">))</span>
  <span class="p">}</span>

  <span class="n">didInput</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">let</span> <span class="n">value</span> <span class="o">=</span> <span class="n">event</span><span class="p">.</span><span class="nf">target</span><span class="p">.</span><span class="nf">value</span><span class="p">.</span><span class="nf">trim</span><span class="p">()</span>
    <span class="n">let</span> <span class="n">matches</span> <span class="o">=</span> <span class="n">value</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="nf">pattern</span><span class="p">)</span>
    <span class="n">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="n">value</span><span class="p">,</span><span class="n">matches</span><span class="p">)</span>

    <span class="sr">//</span> <span class="no">When</span> <span class="n">patterns</span> <span class="n">are</span> <span class="n">loaded</span><span class="p">,</span> <span class="n">we</span> <span class="n">can</span> <span class="n">just</span> <span class="n">fetch</span> <span class="n">the</span> <span class="n">embed</span> <span class="n">code</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">matches</span> <span class="o">!=</span> <span class="n">null</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">this</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="n">matches</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>

    <span class="sr">//</span> <span class="no">No</span> <span class="n">embed</span> <span class="n">code</span><span class="p">,</span> <span class="n">just</span> <span class="n">reset</span> <span class="n">the</span> <span class="n">form</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="n">this</span><span class="p">.</span><span class="nf">reset</span><span class="p">()</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="n">fetch</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="no">Rails</span><span class="p">.</span><span class="nf">ajax</span><span class="p">({</span>
      <span class="ss">url: </span><span class="sb">`/youtube/${encodeURIComponent(value)}`</span><span class="p">,</span>
      <span class="ss">type: </span><span class="s1">'get'</span><span class="p">,</span>
      <span class="ss">error: </span><span class="n">this</span><span class="p">.</span><span class="nf">reset</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="n">this</span><span class="p">),</span>
      <span class="ss">success: </span><span class="n">this</span><span class="p">.</span><span class="nf">showEmbed</span><span class="p">.</span><span class="nf">bind</span><span class="p">(</span><span class="n">this</span><span class="p">)</span>
    <span class="p">})</span>
  <span class="p">}</span>

  <span class="n">embed</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="nf">currentEmbed</span> <span class="o">==</span> <span class="n">null</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="p">}</span>

    <span class="n">let</span> <span class="n">attachment</span> <span class="o">=</span> <span class="n">new</span> <span class="no">Trix</span><span class="o">.</span><span class="no">Attachment</span><span class="p">(</span><span class="n">this</span><span class="p">.</span><span class="nf">currentEmbed</span><span class="p">)</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">editor</span><span class="p">.</span><span class="nf">insertAttachment</span><span class="p">(</span><span class="n">attachment</span><span class="p">)</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">element</span><span class="p">.</span><span class="nf">focus</span><span class="p">()</span>
  <span class="p">}</span>

  <span class="n">showEmbed</span><span class="p">(</span><span class="n">embed</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">currentEmbed</span> <span class="o">=</span> <span class="n">embed</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">embedContainerElement</span><span class="p">.</span><span class="nf">style</span><span class="p">.</span><span class="nf">display</span> <span class="o">=</span> <span class="s2">"block"</span>
  <span class="p">}</span>

  <span class="n">reset</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">embedContainerElement</span><span class="p">.</span><span class="nf">style</span><span class="p">.</span><span class="nf">display</span> <span class="o">=</span> <span class="s2">"none"</span>
    <span class="n">this</span><span class="p">.</span><span class="nf">currentEmbed</span> <span class="o">=</span> <span class="n">null</span>
  <span class="p">}</span>
<span class="p">}</span>

<span class="n">document</span><span class="p">.</span><span class="nf">addEventListener</span><span class="p">(</span><span class="s2">"trix-initialize"</span><span class="p">,</span> <span class="n">function</span><span class="p">(</span><span class="n">event</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">new</span> <span class="no">EmbedController</span><span class="p">(</span><span class="n">event</span><span class="p">.</span><span class="nf">target</span><span class="p">)</span>
<span class="p">})</span></code></pre></figure> 

* [gist with this solution](https://gist.github.com/yshmarov/90377ba51f14df09df03e6442cd7412e){:target="blank"}
* [this question on Stackoverflow](https://stackoverflow.com/questions/61867995/how-to-embed-an-iframe-with-actiontext-trix-on-ruby-on-rails/62407131?noredirect=1#comment114555980_62407131){:target="blank"}
