[Rails] TwitterとYouTubeを埋め込む

学習記録

はじめに

ブログ記事にYouTubeやTwitterなどの埋め込み機能はもはや当たり前です。
URLを入力したら、コンテンツが表示されるように実装していきましょう。

enum用意

Embedモデルのembed_typeカラムにyoutubeとtwitterというenum を設定します。

class Embed < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block

  enum embed_type: { youtube: 0, twitter: 1 }

  validates :identifier, length: { maximum: 200 }
end

記事ブロック見出しアイコンをTwitterに対応させる

Twitterのとき
YouTubeのとき

embedyoutubeなのか、twitterなのか条件分岐させます。 下記で使われているメソッドはembed_typeとしてenumを設定しているので使えています。

module ArticleBlockDecorator
  def box_header_icon
    if sentence?
      '<i class="fa fa-edit"></i>'.html_safe
    elsif medium?
      '<i class="fa fa-image"></i>'.html_safe
    elsif embed?
      blockable.youtube? ? '<i class="fa fa-youtube-play"></i>'.html_safe : '<i class="fa fa-twitter"></i>'.html_safe      # 三項演算子を使ってスッキリ書く
    end
  end
end

自戒の念を込めて

このようにif文の中にif文を作ると、RubocopのLintチェックに引っかかりました。

Metrics/PerceivedComplexity: Perceived complexity for box_header_icon is too high. [8/7]

module ArticleBlockDecorator
  def box_header_icon
    if sentence?
      '<i class="fa fa-edit"></i>'.html_safe
    elsif medium?
      '<i class="fa fa-image"></i>'.html_safe
    elsif embed?
      if blockable.embed_type == 'youtube'
        '<i class="fa fa-youtube-play"></i>'.html_safe
      elsif blockable.embed_type == 'twitter'
        '<i class="fa fa-twitter"></i>'.html_safe
      end
    end
  end
end

記事ブロック挿入画面にTwitterアイコンを追加

記事ブロック挿入画面のアイコンを、YouTubeとTwitterが横並びになるようにしましょう。

d-inline-flex

.d-inline-flex
  i.fa.fa-youtube-play
  i.fa.fa-twitter
'
| 埋め込み

bootstrapで用意されているインラインのFlexコンテナーです。 こちらを使うことで、横並びを実現しています。 ブラウザでは下記のようにレンダリングされています。

<div class="d-inline-flex">
  <i class="fa fa-youtube-play"></i>
  <i class="fa fa-twitter"></i>
</div>

cssを埋め込む

または直接cssを適用させることもできます。

i.fa.fa-youtube-play(style='display: inline')
i.fa.fa-twitter(style='display: inline')

NG例

下記のようにアイコン自体の階層をインデントで変更するのはhtmlの階層としておかしいでしょう。

i.fa.fa-youtube-play
  i.fa.fa-twitter

入力フォーム

simple_formの中で、Youtubetwitterかを選択し、identifierを入力できるようなフォームにします。

.box-body
    = f.input :embed_type, collect: Embed.embed_types_i18n.invert, include_blank: false
    = f.input :identifier

Youtube埋め込み表示ファイル

youtube再生画面の「共有」を押した後に表示される埋め込み用URLというのは、以下の構成になっています。

https://www.youtube.com/embed/11桁のID

各動画は / より後ろの文字列により個別に分類されているので、上記のURLを取得後、 / より後ろの文字列を取得し、「任意のYouTubeのID」に代入すると任意のYouTubeが表示されるようになります。

ID抽出メソッド作成

以下のように、/ を区切り文字としてyoutubeのURLを後ろのidのみを抽出するsplitメソッドをEmbedモデル定義しましょう。

def split_id_from_youtube_url
  identifier.split('/').last if youtube?
end

embedに対して、作成したメソッドを実行して下11桁の文字列だけ取り出して表示させましょう。

.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

tweet埋め込み表示ファイル

tweet埋め込みツールは公式にて用意されています。

Twitter Publish

ここにツイートを貼り付けて埋め込み用HTMLを生成します。

<blockquote class="twitter-tweet">
<p lang="ja" dir="ltr">【ブログ更新】データからも明らか‼️不幸になりたくない人が最重視すべき1つのこと<br><br>普段はお金について情報発信しとるけど、幸福度を決めるのはお金だけじゃないで。<br>
<br>
学歴や収入よりも〇〇の方が、幸福度に影響を与えるんや。<br>
<br>
不幸になる生き方をしてないか確認してな^^
<a href="https://t.co/K1f42WIT0L">https://t.co/K1f42WIT0L</a></p>— 両🦁自由に生きるための知恵を配信中 - リベ大学長 (@freelife_blog) 
<a href="https://twitter.com/freelife_blog/status/1461534705292132354?ref_src=twsrc%5Etfw">November 19, 2021</a>
</blockquote> 
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

無駄な部分を省いて、必要な部分だけ残します。

<blockquote class="twitter-tweet">
<a href="https://twitter.com/freelife_blog/status/1461534705292132354?ref_src=twsrc%5Etfw"></a></blockquote>
 <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

slim形式に変換して整えます。

.embed-twitter
  blockquote.twitter-tweet
    a href="#{embed.identifier}"                          # tweetのURL部分に、embedのidentifierを入れる
  script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"

Rspec

不明な構文

page.all

page.all で要素を全て見つけ出して、インデックスで指定するのがお手軽っぽいです。配列なので、1 が2番目の要素。

page.all(".submit-button")[1].click_button("Submit")  # 2番目の要素
page.all(".submit-button")[2].click_button("Submit")  # 3番目の要素

js: true

JavaScriptを使用しないと操作できない処理をテストします。
Ajaxを使用した処理や、クリックイベントによるモーダル画面の表示など、JavaScriptなしては実行できない操作がある場合にこのタグをつけます。

sleep 秒数

JavaScriptの処理が完了しないうちにテストが先に進んでしまうとテストが失敗するので、JavaScriptの処理が終わるまでテストを停止します。

コメント

タイトルとURLをコピーしました