ActionMailerでSNSシェアボタンを作ろうとしたら少し苦戦しました。
Railsアプリケーションでメールを送信する場面があり、そこにSNSでシェアできる機能を作る機会がありました。
作る前は「TwitterとかFacebookが公式でバッジ提供してくれてるだろうからそれ使えば良いんじゃないの」と思っていました。
facebook:https://developers.facebook.com/docs/plugins/share-button?locale=ja_JP
twitter:https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/overview
公式バッジを使う場合、URLを静的に埋め込むことしかできません。例えば動的にidだけを入れ替えることができません。
ActionMailerだと、HTMLと同じ感じでシェアボタンをメール内に埋め込むということが難しいと分かりました。
結果として、Twitter/Facebookシェアボタンの画像をerbファイルに貼り、その画像のhrefにシェアURLを与えることにしました。
ここで考えることは主に以下の4つ。
- ActionMailer内で画像を扱えるように設定する
- 画像にURLを貼り付ける
- SNSのurlのオプションの付け方
<a>
タグを用いるかlink_to
を用いるか
ActionMailer内で画像を扱う
コントローラの場合と異なり、メイラーのインスタンスには受け取ったリクエストのコンテキストが一切含まれません。
このため、:asset_host
パラメータを自分で指定する必要があります。
:asset_host
がアプリケーション全体で一貫しているのと同様、config/application.rb
でグローバルな設定を行えます。
勿論、config/development.rb
など環境ごとに設定することもできます1。
config.action_mailer.asset_host = 'http://example.com'
画像にURLを貼り付ける
テンプレート内で<img>
タグを生成するためにimage_tag
メソッドが使えます。
ActionView::Helpers::AssetTagHelperで定義されています。オプションの中で画像のサイズを指定したりできます。
= image_tag(source, options = {})
https://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-image_tag
画像にURLを貼るためにlink_to
メソッドを使います。ActionView::Helpers::UrlHelperで定義されています。
= link_to(name = nil, options = nil, html_options = nil, &block)
https://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
nameを指定する場所にimage_tag
メソッドを記述することで画像に対してリンクを設定することができます。
例
<%= link_to image_tag('btn.png'), '/books/index' %>
# 出力結果 -> <a href="/books/index"><img alt="Btn" src="/assets/btn.png" /></a>
URLへのオプションの付け方
Twitter、Facebookのシェア用URLに付けられるオプションについてです。
Twitterでは
https://twitter.com/intent/tweet
というURLがシェア用URLとして存在します。使用できるパラメータは以下です。
text
: ツイート本文(UTF-8およびURLエンコードされている)url
: リンク(URLエンコードされている)hashtags
: ハッシュタグvia
: アカウント名related
: アカウント名in-reply-to
: リプライ先の tweet_id
Facebookでもシェア用URLが用意されています。
https://www.facebook.com/share.php?u=<url>
https://www.facebook.com/sharer/sharer.php?u=<url>
Facebookの方はurlパラメータがなく、twitterで用意されているtextなどのパラメータは使用できません。
<a>
タグを用いるかlink_to
を用いるか、そしてRails特有のこと
以下は失敗例です。ちなみにですが、例の中では「CDアルバムを扱うECサイト」を想定しています。アルバムを購入した時に届く購入完了メールにシェアボタンがついていて「購入しました」とSNSで主張できるというものです。
<a href="https://twitter.com/intent/tweet?text=アルバムを購入しました&url=https://example.com/artists/#{@album.artist.account_name}/artworks/#{@album.artwork.id}&hashtags=example&via=example">
Railsを用いている場合、
&url=https://example.com/artists/#{@album.artist.account_name}/artworks/#{@album.artwork.id}&hashtags=example&via=example
という部分は*_url
もしくは*_path
を用いて表現する方法を考えるのが良いです。
この例だと
artist_artwork_url
もしくは
artist_artwork_path
になります。
*_path
は相対パス、*_url
は絶対パスです。rootを例にとると以下のようになります。
root_path -> '/'
root_url -> 'http://www.example.com/'
*_path
ヘルパーは、メール内では一切利用できません。
メールでURLが必要な場合は*_url
ヘルパー、つまり絶対パスを使う必要があります2。
上の場合artist_artwork_url
を使います。
(viewなどでは*path
を用い、リダイレクトする時のみ*url
を用いるのが一般的です3)
ここで、先ほどあげたシェアURL部分、
https://twitter.com/intent/tweet
https://www.facebook.com/share.php?u=
などはroute.rb
でスコープにして共通化してあげましょう。
config/route.rb
scope host: "www.twitter.com", protocol: :https, port: nil do
get '/intent/tweet', to: redirect("https://twitter.com/intent/tweet"), as: :twitter_share
end
scope host: "www.facebook.com", protocol: :https, port: nil do
get '/sharer/sharer.php', to: redirect("https://www.facebook.com/sharer/sharer.php"), as: :facebook_share
end
こうすることで逐一URLを書かずにすみます。
<%= link_to image_tag('twitter.jpg'), twitter_share_url(text: 'アルバムを購入しました', url: artist_artwork_url(@artwork.artist, @artwork), hashtags: 'example', via: 'example') %>
<%= link_to image_tag('facebook.jpg'), facebook_share_url(u: artist_artwork_url(@album.artist, @album.artwork)) %>
[2020.09.17追記] ActionMailerでのファイルの添付
上記を実行し、ローカル上では画像が表示されるものの、サーバーにあげると表示されませんでした。
Railsガイドにファイルの添付について説明がありました。4
Action Mailer 3.0はファイルをインライン添付できます。この機能は3.0より前に行われた多数のハックを基に、理想に近づけるべくシンプルな実装にしたものです。インライン添付を利用することをMailに指示するには、Mailer内のattachmentsメソッドに対して#inlineを呼び出すだけで済みます。
in mailers/hoge.rb
attachments.inline['filename.jpg'] = File.read('/path/to/filename.jpg')
これをviewに反映させます。
続いて、ビューでattachmentsをハッシュとして参照し、表示したい添付ファイルを指定することができます。これを行なうには、attachmentsに対してurlを呼び出し、その結果をimage_tagメソッドに渡します。
<p>Hello there, this is our image</p>
<%= image_tag(attachments['image.jpg'].url) %>
単にimage_tagを使うだけではダメで、mailerのファイルでインライン添付の設定をする必要がありました。
これを反映させたサンプルコードが以下です。
<%= link_to image_tag(attachments['twitter.jpg'].url), twitter_share_url(text: 'アルバムを購入しました', url: artist_artwork_url(@artwork.artist, @artwork), hashtags: 'example', via: 'example') %>
<%= link_to image_tag(attachments['facebook.jpg'].url), facebook_share_url(u: artist_artwork_url(@album.artist, @album.artwork)) %>
オプションの付け方、link_to
とimage_tag
の組み合わせ方に注意しながら、SNSシェアボタンを記述することができました。
最後に
もし本記事に関して修正依頼・ご質問などございましたらhttps://twitter.com/o8n_project宛にご連絡いただけると幸いです。
参考文献
主要 SNS(Twitter, Facebook, LINE)への共有リンクの設定方法
Rails - 名前付きルートにおける_pathと _urlの違いと使い分け
What is the difference between _url and _path while using the routes in rails