「買ってよかったもの」をまとめるWebサービスを作りました！【Rails + Vue.js】

**前半は作った経緯からリリース後のあれこれについて、
後半はRailsやVue.js、SPA、SEOなど、技術的な話を書いていきます。**

# サービス編

『Recomint - おすすめアイテム共有サイト』

~~[https://recomint.net](https://recomint.net)~~ 2021/9/1追記: 検討した結果クローズしました :bow: 

PC
![recomint_ss.png](https://qiita-image-store.s3.amazonaws.com/0/151137/fa400015-282d-0bf6-e046-727c4591534a.png)

SP
![recomint_ss2.png](https://qiita-image-store.s3.amazonaws.com/0/151137/1bb82bf1-8afa-1c09-1b90-b9cbbb446828.png)


## サイトの説明
よく年末になると「2017年買ってよかったもの10選！」とかって記事が出てくると思うんですが、ああいうおすすめ商品のまとめを簡単に作成できるサイトです。

基本的にamazonの商品ベースになるのですが、モノに限らず、「絶対見るべき映画ベスト5」とか「PS4の神ゲー5選」みたいな感じで色んなおすすめを作れるようになっています。

サイト名は「Recommend」+「Mint」で「Recomint」です。
（最初は「絶対買ったほうがいい.com」って名前でした）

## 作った経緯
まず、僕は転職して2018年1月から次の会社になります。
で、転職先でメインに使っているのがrailsらしいのですが、僕はruby自体未経験なので入社までになんか作っておくか、と思い作りました。

### 僕「目指せ収益化！」
もうひとつの目的として、サービスを作ってお金を稼いでみたかったのがあります。

だから、商品紹介ブログの執筆をそのまま利用者に肩代わりしてもらうような安直なサービスを思いついたわけです。

### Amazonアソシエイトさん「だめ」
はい…、あっさり審査で却下されました。

審査落ちの理由は知らされません。
ともかくこのサイトでどれだけ商品が売れようと僕の利益はゼロです。

## はじめてのツイッター広告
単に公開しただけでは使われないだろうと思い、これも初の試みとしてやってみました。
個人でも小額から広告を出せるようです。

さっきも書いた通り、サイトが使われようがリターンはありませんが、「収益化したい」＝「実際にお金が欲しい」ってわけでは全くなく、ただ色々やってみたいだけなので赤字なのはノープロブレム。

### とりあえず6000円分の広告出してみた
自分のツイートをそのまま広告として使うか、広告用に別途専用のツイートを作成して使えるようです。

ひとまず普通に「サービス作ったよ」的なお知らせツイートを投稿。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">「買ってよかったもの10選！」や「おすすめの○○ベスト5」みたいなまとめを作成するWebサービスをつくりました。<a href="https://t.co/NJOFwwpszI">https://t.co/NJOFwwpszI</a></p>&mdash; らいね (@Laineus) <a href="https://twitter.com/Laineus/status/942383089623240704?ref_src=twsrc%5Etfw">2017年12月17日</a></blockquote>

（いつもいいねやリツイートありがとうございます）

試しにこのツイートと、サービス自体の紹介とはちょっとずらしたアプローチの広告2枚を計6000円分試しました。

ターゲットとか色んな設定項目がありましたが、よく分からないところはてきとうに。。

そして結果は以下のとおり、

|画像|表示回数|クリック数|クリック率|単価|総額|
|---|---|---|---|---|---|
|![MYoE9Q1d.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/5f1286d9-eaa2-7ee3-d4af-cbec0758e291.jpeg)|3,711回|22回|0.59%|91円|2,000円|
|![0Ff8J2q3.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/e1b82b8b-c7c0-c89c-b597-fc3b8c2053ac.jpeg)|1,979回|10回|0.51%|213円|2,127円|
|![VDfcJeEE.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/b6f5003e-e708-cfc7-f157-4b00e8709a43.jpeg)|1,918回|12回|0.63%|156円|1,873円|

あっと言う間に6000円溶けたんですが…。1回クリックしてもらうのに100~200円って高すぎません…？

### 2000円分再チャレンジ

と思ったら、入札設定というものを「自動入札」にしていたのがよくなかったようで、この項目を明示的に指定してあげると、単価がその額に近くなるように配信されるみたいです。

コレを25円に設定しなおして、もう一度2000円分試してみました。

|画像|表示回数|クリック数|クリック率|単価|総額|
|---|---|---|---|---|---|
|![MYoE9Q1d.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/5f1286d9-eaa2-7ee3-d4af-cbec0758e291.jpeg)|11,075回|72回|0.65%|22円|1,565円|
|![0Ff8J2q3.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/e1b82b8b-c7c0-c89c-b597-fc3b8c2053ac.jpeg)|1,153回|4回|0.35%|25円|100円|
|![VDfcJeEE.jpeg](https://qiita-image-store.s3.amazonaws.com/0/151137/b6f5003e-e708-cfc7-f157-4b00e8709a43.jpeg)|5,535回|14回|0.25%|23円|325円|

クリック単価が25円以内に収まるように配信されました！
代わりに2000円分配信しきるまで半日くらいかかりました。

今回は、一番上のツイートが集中的に課金されたんですが、効率のよかったものが自動で優先されるんでしょうか。

### サイト側の成果は？

登録者数プラス4、投稿してくれた人が1、でした。
きっと本業の方が同じ額を広告に使ったら全然違う結果なのでしょう…。

（ちなみに、12/18以前にある投稿は、自分で書いたり友達が書いてくれたものです）


# 実装編

ここからは技術的な話です！

## はじめてのruby
初体験。

特に言うことないんですが、無理に文句を言うとすると、構文やビルトイン関数について「色んな書き方ができる」ってところがあんまり好みではなかったです。

`if`や`unless`あたりはともかく、例えば、文字列クラスの「文字数を調べる関数」は`length`と`size`、同じ内容のものが2つありますが、両方必要だった理由とかあるんでしょうか？

他の人がどちらを使うかわからないので、結局は両方について覚える必要がありますし、そもそも書き方が混在するのもちょっと嫌だな、と。

逆に極端なGolangを使っていたせいでそう思うのかもしれません。

### Rails
似た系統のLaravelを使ったことがあるので、便利さは体感済みなのですが、やはり便利ですね。
LaravelとRails、どちらも使っていて大きな差は感じないので、もしこの2つから選べと言われるとどっちでもよい感じです。

### Rails apiモード
SPAで実装するなど、バックエンドはjson apiだけ実装すればよい場合、Rails5のapiモードが使えます。
通常のRailsから`sass-rails`や、`jquery-rails`といった、フロントエンドの実装に必要なものが省略されるようです。

```sh
$ rails new projectname -d mysql --api
```

今回は、railsが初回htmlを返し、さらに初回htmlのhead内を動的にしたかった（後述）ので、apiモードじゃ厳しいのかと思いましたが、普通に大丈夫でした。htmlも返せますし、erbも動きます。

## Vue.jsいいゾー
今まで一番シンプルなRiotを好んで使っていたんですが、両方を使い込んでいくほどVue.jsのほうがいいなーと思い始めました。

長くなるので詳しくは語りませんが、例えばform周りの実装のしやすさとかに結構差を感じます。

また、僕は趣味のプロダクトにおいては「フロント資材絶対ビルドしないマン」だったわけですが、今回は素直にwebpackを導入しました。

vue-cliで簡単にVue.js+webpackの環境を作れるので、僕と同じ病気の人は試してみて下さい。


## SPAとSEO
SPAで作ったサイトは今回以外にもいくつか運用していますが、SPAのSEOはまだまだ研究中です。

憶測がメインになりがちなので、話半分読んでください。

fetch as google（インデックスリクエスト）の際、対象のページ+リンク先をクロールしてもらうオプションがあるのですが、それを実行してもリンク先はインデックスされませんでした。

結局記事ごとに申請していったのですが、jsレンダリング部分は認識されたりされなかったり。

「GoogleはSPAも大丈夫！」「SPAはSEOで不利！」と両方聞きますが、きっとどっちも間違っていないと思います。
うまく認識されなくても、数カ月後には直っていたり。不安定です。

### なんちゃってSSR

Googleを信じて待つ手もありますが、今回はある程度の情報をサーバーで生成します。

理由は、せめてtitleとdescriptionは確実に表示されて欲しいのと、仮にGoogleが大丈夫でも、jsを解釈しないTwitterやFacebookにogpを読ませるために、結局サーバー側での動的な出力は避けらないためです。

ただし、Isomorphicとかは考慮せず、今回は単にrailsでhead内（title、meta、ogp）のみ出力することにしました。

内容はめちゃくちゃ単純で、記事id=1のページなら、モデルから記事1を取得して、erbでtitleなどを吐き出すだけです。

一方Vue.jsは、head内に関してはtitleタグのみ更新するようにしました。

### エラーページやステータスコード

エラーは、初回のアクセスに限り、そのURLに対する正しいステータスコードを返すように実装します。

これは、前項のなんちゃってSSRと一緒に判定しています。

SPA遷移時はどうしようもないので、apiからの結果が404だったら404ページぽいコンポーネントをマウントするだけです。


## SPAのページスピード

Google Page Speed InsightsにてGoodを獲得！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/151137/c361aa75-409b-7f22-8eae-f68a57e19bf9.png)

※ いまは機能追加しているうちに上記よりスコア落ちてしまいました

全く同じサイトで、SPA vs レガシーでページビューの差とか研究してみたいです。

# おわり

ぜひ使って下さい！