すること
今回はGET statuses/oembed — Twitter Developers を用いてツイッターカードを表示します。
埋め込みHTMLを取得するためには認証は必要ないので、単純なリクエストでデータを取得することが可能です。
流れは以下の通りです。
入力されたURLからIDを取得
リクエストを送信してデータを取得
URL, jsonをデータベースに保存
保存したデータを表示
開発環境
Ruby 2.6.5
Rails 5.2.3
MySQL 8.0.19
コントローラ
別段珍しいことはしていません。
redirect_to, renderは適当です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class TweetsController < ApplicationController
def create
if @tweet . create ( tweet_params )
redirect_to tweet_path ( @tweet )
else
render :new
end
end
def update
@tweet = Tweet . find ( params [ :id ] )
if @tweet . update ( tweet_params )
redirect_to tweet_path ( @tweet )
else
render :edit
end
end
private
def tweet_params
params . require ( :tweet ) . permit ( :url )
end
end
モデル
事前に、jsonを入れる予定のt_json
カラムをマイグレーションで作成しておきます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# == Schema Information
#
# Table name: tweets
#
# id :bigint not null, primary key
# url :string(255) not null
# t_json :json not null
# created_at :datetime not null
# updated_at :datetime not null
#
class Tweet < ApplicationRecord
validates :url , presence : true , length : { maximum : 200 }
end
このままでは、入力したurlしか保存されません。ということで、urlからt_jsonを取得し保存するまでの流れを順に追っていきます。
1. 入力されたURLからIDを取得
URLは、例えばhttps://twitter.com/Interior/status/507185938620219395
という形になりますが、リクエストに必要なのはIDの507185938620219395
の部分だけです。
ということで、入力されたURLからIDとなる文字列を抜き出すtweet_id
というインスタンスメソッドを作成します。
1
2
3
def tweet_id
url . split ( '/' ) . last
end
ちなみに、tweet.tweet_id
というような書き方で、モデルの外部からもIDを取得できます。
2. リクエストを送信してデータを取得
TwitterAPIにGETリクエストを送ります。
curlコマンドでは以下のようなコマンドになります。
1
$ curl 'https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FInterior%2Fstatus%2F507185938620219395'
これをRubyで実装します。2つの方法を挙げます。
open_uriを用いる方法
1
2
3
4
5
def tweet_json
url = "https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FInterior%2Fstatus%2F #{ tweet_id } "
responce = OpenURI . open_uri ( url ) # リクエストを送り、返り値をresponceに代入
ActiveSupport :: JSON . decode ( responce . read )
end
Net::HTTPを用いる方法
1
2
3
4
5
6
def tweet_json
url = "https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FInterior%2Fstatus%2F #{ tweet_id } "
uri = URI . parse ( url )
responce = Net :: HTTP . get ( uri ) # リクエストを送り、返り値をresponceに代入
JSON . parse ( responce )
end
RubyのHTTPリクエストを送る方法の性能比較 によると、Net::HTTP の方が速いようです。
これで以下のようなjson形式のデータを返すメソッドを作成できました。
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"url" : "https://twitter.com/Interior/status/507185938620219395" ,
"author_name" : "US Dept of Interior" ,
"author_url" : "https://twitter.com/Interior" ,
"html" : "<blockquote class=" twitter-tweet "><p lang=" en " dir=" ltr ">Happy 50th anniversary to the Wilderness Act! Here's a great wilderness photo from <a href=" https : //twitter.com/YosemiteNPS">@YosemiteNPS</a>. <a href="https://twitter.com/hashtag/Wilderness50?src=hash">#Wilderness50</a> <a href="http://t.co/HMhbyTg18X">pic.twitter.com/HMhbyTg18X</a></p>— US Dept of Interior (@Interior) <a href="https://twitter.com/Interior/status/507185938620219395">September 3, 2014</a></blockquote>n<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>",
"width" : 550 ,
"height" : null ,
"type" : "rich" ,
"cache_age" : "3153600000" ,
"provider_name" : "Twitter" ,
"provider_url" : "https://twitter.com" ,
"version" : "1.0"
}
tweetを保存する前に、before_save
を用いてt_json
に値を入れることにします。
set_json
メソッドの役割は、URLが変更されていた場合、t_json
に値を入れる というものです。
外部APIを叩きすぎるのはよくないので、URLが変わっていない場合は特に変更しません(今回の例では他に変更しうるカラムがないので別に必要ないのですが)。
1
2
3
4
5
6
7
8
9
10
11
class Tweet < ApplicationRecord
before_save :set_json # 追加
def set_json
self . t_json = tweet_json if will_save_change_to_url?
end
def tweet_json
# TwitterAPIから取得したJSONデータを返す
end
end
最終的なモデル
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Tweet < ApplicationRecord
before_save :set_json
validates :url , presence : true , length : { maximum : 200 }
def tweet_id
url . split ( '/' ) . last
end
private # 以下のメソッドは外部から呼び出さないのでprivateにする
def set_json
self . t_json = tweet_json if will_save_change_to_url?
end
def tweet_json
url = "https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FInterior%2Fstatus%2F #{ tweet_id } "
uri = URI . parse ( url )
responce = Net :: HTTP . get ( uri )
JSON . parse ( responce )
end
ビュー
Twitterカードを表示するにはjsonの"html"
をそのままHTMLとして出力すればいいので、ビューファイルで以下のように記述します。
1
<%= @tweet . t_json [ 'html' ]. html_safe %>
ツイート情報を取得する際のオプション
1
"https://publish.twitter.com/oembed?url=https%3A%2F%2Ftwitter.com%2FInterior%2Fstatus%2F #{ tweet_id } &omit_script=true"
このように&
でつなげます。(パラメータの種類については公式ページ 参照)
omit_script=true
にすると、<script>
部分を除いたHTMLが返されるので、1ページに複数のツイートを表示する場合はおすすめです。
1
2
3
4
5
< % @tweets.each do | tweet | %>
<%= tweet.t_json['html'].html_safe %>
< % end %>
<%= javascript_include_tag '//platform.twitter.com/widgets.js' %>
リンク