【Rails】YoutubeとTwitterをAPIを使わずに記事に埋め込む
実装したいこと
記事投稿アプリで、YoutubeやTwitterを記事に埋め込みたい。
URLを入力したら、埋め込み用に変換して、記事に反映させたい。
Slim記法が苦手で、HTMLに反映させるのに手こずってしまいました。。便利ツールを使ってようやくできた。(後述)
データの流れ
- ユーザーがYoutubeかTwitterを選択し、入力フォームにURLを入力する。
- ユーザーの入力した値を受け取り、保存する。
- ユーザーが入力した値を記事に埋め込める形式に変換する。
- Viewに反映される。
実装の流れ
- ユーザーの入力値を受け取るカラムを用意する。
- 入力フォームを用意する。
- 埋め込みに対応してくれるhtmlを返すviewを用意する。
- 受け取ったURLを変換するメソッドを準備する。
カラム準備
ユーザーが入力した値を保存するためのカラムを用意します。
embed_typeでYoutubeかTwitterを選択します。
identifierでURLを保存します。
class Embed < ApplicationRecord
enum embed_type: { youtube: 0, twitter: 1 }
validates :identifier, length: { maximum: 200 }
end
入力フォーム
YoutubeかTwitterかを選択し、identifierを入力できるように設定します。
(gem 'simple_form'を使っています。)
(略)
.box-body
= f.input :embed_type, collect: Embed.embed_types_i18n.invert, include_blank: false
= f.input :identifier
(略)
View
Youtube 公式
動画と再生リストを埋め込む - YouTube ヘルプ
Twitter公式
タイムラインを埋め込む方法
Overview | Docs | Twitter Developer
Twitter Publish
HTMLをSlimに変換できる
HTML2slim
Youtubeのケース
上記のYoutube公式の動画にも丁寧に解説がありますが、埋め込みたいYoutube動画ページで、「共有」→「<> 埋め込む」を選択すると、埋め込み用のHTMLを用意してくれます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/ojdbDYahiCQ" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
私はSlimを使っているので、このHTMLをSlim記法へ変換します。
ただし、とても苦手なので上記のサイトを使っています…
YoutubeのURLを切り取る
Youtubeの埋め込み用URLは以下の構成になっています。
https://www.youtube.com/embed/動画一意のID
最後の/までは固定値として設定し、ユーザーの入力したURLのうち、最後の/以下だけを受け取り、反映させていきます。
最初私は、embed.identifier.last(11)で末尾の11字だけ切り取って実装していたのですが、これだと開始位置を指定したURLを貼り付けられた場合に動かなくなってしまいます。
なので、以下のように、/以下を取得するメソッドを作っておきます。
splitメソッドで、/で区切りをつけた配列を返して、そのlast末尾部分を取得しています。
(略)
def split_id_from_youtube_url
# YoutubeならIDのみ抽出
identifier.split('/').last if youtube?
end
ruby:
embed = local_assigns[:embed]
width = local_assigns[:width] || 853
height = local_assigns[:height] || 480
.embed-youtube
= content_tag 'iframe', nil, width: width, height: height, src: "https://www.youtube.com/embed/#{embed.split_id_from_youtube_url}", \
frameborder: 0, gesture: 'media', allow: 'encrypted-media', allowfullscreen: true
/ Youtube公式に乗っている埋め込み用のHTMLを出力する形にする。
/ #{embed.identifier.last(11)}でIDを切り取ると、開始秒指定されたときにOUT
Twitterのケース
上記の公式に乗っているように進めていきます。
貼り付け用に変換してくれる公式ツールがあるので、ここにツイートを貼り付けて埋め込み用HTMLを生成します。
Twitter Publish
<blockquote class="twitter-tweet"> <p lang="en" dir="ltr">A huge thank you to all of the bosses who are making voting a priority for their employees and giving people the time they need to vote. I’m doing that for my team 😘😘 Please share your voting plans with me!</p>— Lady Gaga (@ladygaga) <a href="https://twitter.com/ladygaga/status/1317133489829937152?ref_src=twsrc%5Etfw">October 16, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
これの無駄な部分を省いて、この部分があれば良さそう
<blockquote class="twitter-tweet"> <a href="https://twitter.com/ladygaga/status/1317133489829937152?ref_src=twsrc%5Etfw"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
これを上記サイトでSlimへ変換して整えればOK
.embed-twitter
blockquote.twitter-tweet
a href="#{embed.identifier}"
script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"
泥臭くやってしまったけど、もっとスマートな方法があるかもしれないです。。
RSpecメモ
# 更新ボタンが同じページにいくつかあるとき… page.all('.box-footer')[0].click_button('更新する') # Youtubeの埋め込みを確認したいとき expect(page).to have_selector("iframe[src='https://www.youtube.com/embed/ojdbDYahiCQ']")