いいねボタンがないブログ
本ブログ、いいねボタンが ありませんでした。
だから、作っちゃいました。っていう記事です。
構成
上図のように
記事ページからAPIサーバにリクエストを送り、 いいねの数を取得・加算します。
記事ページからAPIサーバへのリクエスト部分(クライアント)には Vue + axios を使用。
APIサーバは Rails で実装しました。
(以前から Slackのスラッシュコマンド用に使用していたAPIサーバを流用しました)
APIサーバ
Rails で APIサーバを建てる方法に関しては、
以前に Qiita で 入門記事 書いたのでそちらをご覧ください。
(少し古い記事ですが、そんなに問題はないはずです)
DB にテーブル作成
今回、ブログ記事を管理するために、下記のテーブルを作成しました。
mysql> describe blog_posts;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| count | varchar(255) | NO | | 0 | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
title
には、日本語のタイトル(本記事だと『【WEB API(RAILS) + VUE.JS】ブログのいいねボタン自作してみた』)ではなく、
記事ファイル(マークダウン)の名前(本記事だと『good_api』, 拡張子抜き)が入ります。
Web上の記事データと APIサーバのレコード をどうやって結びつけるか考えたとき、
ページが持っている記事の情報って、 URL に含まれる 記事ファイル名 しかないなぁ…と考え、
URL から取得した 英title と テーブルの title
が一致するものを探すようにしました。
CORSの設定
今回重要なのは CORS の設定です。
CORS を説明するとなると、 CSRF の説明やらなんやらで、とても長くなり、本題からかなり脱線するので
今回は こちらのサイト をご紹介するだけにしておきます。
僕的に一番分かりやすかったです。
・
・
・
では、本題の CORS の設定についてですが、
Rails における CORS の設定はとても簡単です。
Gemfile に
rack-cors
を追加Rails で生成した Gemfile にデフォルトで入っていますが、コメントアウトされています。
コメントを解除してあげましょう。
# Gemfile …省略 # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible gem 'rack-cors' …省略
cors.rb
を編集こちらも元から存在するファイルです。
中身に関しては、コメントを解除してあげるだけでOKです。
# <Rails Root Directory>/config/initializers/cors.rb Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'https://yyh-gl.github.io' resource '*', headers: :any, methods: [:get, :post, :options] end end
origins
で指定した場所からのアクセスに関しては、同一生成元ポリシーを少し無視してアクセスを許可します。
ワイルドカードによる指定もできます。
今回は、僕のブログからのアクセスのみを許可します。
resource
によってアクセスを許可するリソースを指定できます。resource
で許可したリソースに対して、headers
およびmethods
で指定したヘッダおよびメソッドのみを受け付けます。こちら を見ていただければ、より詳しい設定方法が分かると思います。
今回実装するAPIは GET と POST しか使わないので
methods: [:get, :post, :options]
となっています。options
は プリフライトリクエスト と言って、事前にサーバに対してリクエストを送信しても大丈夫か問い合わせるさいに使用します(参考 )。
忘れずに追加しましょう。
以上で、Rails における CORS の設定は完了です。
クライアントの実装
次は、記事ページからリクエストを送る部分です。
まず、HTMLファイルはこんな感じです ↓
<html>
<div id="GoodCounter">
<good-counter></good-counter>
</div>
</html>
<script src="/tech-blog/js/axios.min.js"></script>
<script src="/tech-blog/js/vue.min.js"></script>
<script src="/tech-blog/js/vue_app.js"></script>
中の処理を説明すると、
IDが GoodCounter
の div
要素の部分に Vue コンポーネント(後述)を入れ込んでいます。
script
タグは、上から axios, Vue, Vue コンポーネント を読み込んでいます。
次に Vue コンポーネントです。
// vue_app.js
Vue.component('good-counter', {
template: '<button v-on:click="addCount">\n' +
'<i class="far fa-thumbs-up"></i> いいね {{ good_count }}\n' +
'</button>',
data: function () {
return {
good_count: "-",
}
},
mounted () {
// URL から記事情報を取得
let paths = location.pathname.split('/');
// URL のタイトル部分のみを抽出
// GET /posts/:title への リクエストURL を作成
let reqUrl = '<server url>' + paths[paths.length - 2];
axios
.get(reqUrl)
.then(response => this.good_count = response.data.post.count)
},
methods: {
addCount: function (event) {
// URL から記事情報を取得
let paths = location.pathname.split('/');
// URL のタイトル部分のみを抽出
// POST /posts/:title/good への リクエストURL を作成
let reqUrl = '<server url>' + paths[paths.length - 2] + '/good';
if(event) {
axios
.post(reqUrl)
.then(response => this.good_count = response.data.after)
}
}
}
});
// root インスタンスを作成
new Vue({
el: '#GoodCounter',
});
いろいろ書いていますが、 URL から記事タイトルを取得し、
それを基にリクエストを送っているだけです。
Vue コンポーネントのマウント時に いいねの数を GET しています。
そして、いいねボタンが押されるたびに addCount()
が実行されて、 いいね が加算されます。
Vue の SFC を使いたかったのですが、勉強不足で実現できず、このような実装になりました。
詳しい人ぜひ教えてください。
完成!
できあがったものは、↓ の方にスクロールしていったら実物があるので見てみてください
だれがいいねしてくれたかは分からないですが、 誰かがしてくれた という事実を噛み締めたいと思います。
Vue は僕の会社でも使われているので、今後も積極的にキャッチアップを続けていきたいです。
フロントの知識もっとつけていきたいですねー👾
(APIサーバへのアクセスを制限しないとな…)