【個人開発】チャットBotのAppStoreが1週間で出来上がるまで（rails）

![thumbnail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/914b4417-6c3b-7cce-1f49-912cb81fc155.png)
## はじめに

チャットBotや音声アプリのダウンロードサイトを作りました。2022年にはチャットボットの市場規模は132億円規模になる！アメリカでは成人の1/4にスマートスピーカーが普及している！など、このあたりの産業は高騰してくのが目に見えていますので。

今のうちに、こういう横断的なサイトを立ち上げておけばまだ間に合うかもしれない。そもそも、それっぽいのが国内には見当たらなかったので作ってみよう！と決めて、1週間で仕上げました。今回は、コードを書き始めて、リリースするまでをオープンに書いていきたいと思います。

**「個人開発に挑戦してみたいな。」**と考えている方にオススメです！

## Botcampとは
<img width="1249" alt="スクリーンショット 2019-07-13 20.27.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/7ca68a8d-8bf7-526d-6fa4-2ae3a5e503e3.png">

URL：[http://botcamp.jp](http://botcamp.jp)

AppStoreや、Google Play Storeってありますよね？これらのプラットフォームでは、スマホアプリをダウンロードできますが、[Botcamp](http://botcamp.jp)ではチャットBotや音声アプリをサイトからダウンロードできます。

できることは、まず「Botを登録する」。運営元じゃなくても、会員登録しなくても、Bot登録はできるような仕様にします。何といっても、このBot数こそがサイトを成り立たせるために必須条件となるので、なるべく登録していただきたいところ。

次に、「Botをダウンロードする」です。といっても、各プラットフォームが提供しているURLをBotごとに設定しておくだけです。

最後に、「Botをレビューする」になります。App Storeのデザインにだいぶ寄せてます（笑）Botやアプリの品質を評価できる部分なので、Bot数を増やしていったあとに、力を入れて増やしていきたい部分です。

おまけに、Slackのワークスペースをコミュニティとして用意してみました。とりあえず、会員登録した人を全員ワークスペースに招待していくという状況を作ってみようかと思います。これに関しては、どうなるかは分からないですが、Botマニアたちが情報交換できるコミュニティ的になれれば嬉しいですね。ちょっと実験的に入れてみた感じです。

## 1週間で出来上がるまで

### Day1
<img width="990" alt="スクリーンショット 2019-07-13 0.02.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/87f16a6f-6b3b-2f3b-8735-65238f4eb892.png">


Gitを確認してみたところ、2019年7月8日から開発をスタートしています。初日はRails newして、トップのデザインをコーディングしただけでした。デザインに関しては、ベースは「[開発会議](https://devtalk.jp/)」や「[個人開発のフリマ](https://devmart.jp/)」で使っているものを流用しています。

MVPを作る過程において、デザインに力を入れる必要があるプロダクトではないので、毎回流用してリソースをカットしています。ただ、どうしてもこだわり的にレスポンシブサイトが好きになれなくて、pcとspを分けています。

昔は`gem jpmobile`というライブラリを使っていたのですが、Rails 4.1.0で追加されたActionPack Variantsを使うようになりました。

```Ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :detect_device_variant

  private

  def detect_device_variant
    request.variant = :sp if is_mobile?
  end
end
```

```Ruby:app/models/concerns/user_agent.rb
module UserAgent
  extend ActiveSupport::Concern

  def is_mobile?
    request.user_agent =~ /iPhone|iPad|Android/
  end
end
```

これで、HTML側は切り替わってくれるので、スタイルシートもpcはpc直下のディレクトリのみ、spはsp直下のディレクトリのみ読み込んでくれるように設定を変更しておきます。

```erb:app/views/layouts/application.html.erb

<%= stylesheet_link_tag    "application", :media => "all" %>

## pc直下のみに変更
<%= stylesheet_link_tag 'pc/style', media: 'all', "data-turbolinks-track" => true%>
```

初日で本番環境（Heroku）にはあげました。ドメイン購入しましたし、Amazon s3（画像サーバー）、SES（メールサーバー）も設定しました。こういう本番を意識した開発をDay1からするのは、個人開発の精神面で大切な気がしますね。

### Day2
<img width="989" alt="スクリーンショット 2019-07-13 0.19.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/ee9ce210-f5ff-228c-7d67-1d91b6b4f84b.png">

Userの認証〜管理までを実装しました。`gem devise`を使っていて、ライブラリとしては賛否両論ありますが、管理画面`rails_admin`と連携するところもありますし、初心者が爆速でローンチするんだったら、使ってokだと思います。

このあたりは、完全に今まで作ってきたサービスのコピペです。振り返ってみると、コミュニティ系のサイト作るならここまでは毎回同じなのでどっかに置いておいても良いですね。

### Day3
<img width="990" alt="スクリーンショット 2019-07-13 1.00.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/a5ab866e-f3cf-1872-2e86-3ff80f6c56c6.png">

Bot関連のCRUDを作ってみました。少しいつもと違ったのが、Botを作成する際に運営元（Botを配信している会社/個人開発者）を追加するのですが、これを既存のものからか、新しく追加できるのを選べるようにするパターンがあるのです。

まず、`Maker`モデルを用意しました。`Bot`モデルとは一対多の関係になります。もっと良いやり方がありそうですが、`attr_accessor`を使って、これがある場合には運営元を更新して、新しいものを追加するようにしました。

```ruby:app/models/bot.rb
  attr_accessor :bot_maker
  attr_accessor :bot_maker_url
```

```Ruby:app/controllers/bots_controller.rb
  def create
    @bot = Bot.create(create_params)
    if @bot.bot_maker.present?
      @maker = Maker.create({
          name: @bot.bot_maker,
          website: @bot.bot_maker_url
        })
      @maker.save
      @bot.maker_id = @maker.id
    end
    if @bot.save
      flash[:success] = "新しくボットが追加されました！"
      redirect_to @bot
    else
      flash[:alert] = "ボットの追加に失敗しました。"
      redirect_to new_bot_path
    end
  end
```

カテゴリと、お気に入り機能はチュートリアルにあるくらいの感覚で実装しました。いつもと同じです。

### Day4
この日、Mac Book Proが急に死にます。Apple Storeへ重病の我が子を看てもらうように急ぎましたが、4時間待たされた上に完治するまで7営業日かかると宣告されました。スペアPCの開発に急遽移行へ。
<img width="981" alt="スクリーンショット 2019-07-13 1.09.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/aa057b99-588a-7c5c-8b9b-c505fb21e901.png">

`Review`と、`Type`（プラットフォーム）、`BotImage`（ボットの複数画像）を実装しました。プラットフォームはLINEや、MessengerなどのプラットフォームごとのダウンロードURLを入力するところです。Botを入力するときに、同時に入力できるようにしたいので、`gem cocoon`を使いました。

`Type`は、`Bot`と多対多。`BotImage`は一対多で関係を構築しました。`Type`の方の例を載せておきます。

```erb:app/views/bots/new.html.erb
  <section class="feed">
    <div class="box">
      <h2>プラットフォーム</h2>
      <div class="formContainer">
        <div class="imageContainer">
          <%= f.fields_for :bot_types do |t| %>
            <div id="types">
              <%= link_to_add_association "プラットフォームを追加", f, :bot_types, partial: 'type' %>
            </div>
          <% end %>
        </div>
      </div>
    </div>
  </section>
```

```erb:app/views/bots/_type.html.erb
<div class="nested-fields">
  <div class="formItem flexContainer typeContainer">
    <div class="label">
      <%= f.collection_select :type_id, Type.all, :id, :name, {class: "selectType"} %>
    </div>
    <div class="formInput">
      <%= f.text_field :url, placeholder: "ホームページや、ダウンロードリンクを入力してください" %>
    </div>
  </div>
  <p><%= link_to_remove_association "プラットフォームを削除", f %></p>
</div>
```

### Day5
夜ご飯を料理してたら、シェアメイトのオリーブオイルが棚から落ちてきて派手に割れる、右中指からまあまあ出血しました。キーを打つのが極めて困難に。
<img width="982" alt="スクリーンショット 2019-07-13 1.25.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/e9207c5e-2136-3a4a-8370-1d7d62f21245.png">

この日は結構微調整が多かったですね。検索機能をつけたり、カテゴリ、プラットフォーム、運営元のURL指定がIDになっていたので、slugを作成して、それに変更しました。`botcamp.jp/types/`を`botcamp.jp/types/line`に変えた感じですね。

```ruby:config/routes.rb
  resources :types, param: :slug
```

```ruby:config/controllers/types_controller.rb
class TypesController < ApplicationController
  def show
    @type = Type.find_by_slug(params[:slug])
  end
end
```

### Day6
<img width="983" alt="スクリーンショット 2019-07-13 1.31.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116375/e7c6b844-180c-34dc-1aeb-a35ffe9ada25.png">
この日はほとんどコードを書いていません。デザインや、仕組みの微調整をしたくらいですね。

ひたすら、ボットを探していました。スクレイピングをするのもよぎったのですが、なかなか良い感じのスクレイピング先が思い浮かばなくて。とりあえず、手で探し、手で入力するような、労働集約的な作業をしました。それでも、40ちょっとしか見つからなくて泣きそうになりました。

100は欲しかったのですが、気が滅入りそうなので、とりあえず、出して、毎日ちょこちょこ入れていこうと決意しました。

### Day7
リリースします。リリース時にやることはそこまでないのですが、[開発会議](https://devtalk.jp)の週一で送っているニュースレターを一日ずらして、リリースのことを含んだ文書にする。もちろん、開発会議も更新する。

そして、TwitterとこのQiita記事を投稿するくらいです。あと、落ち着いたら、[Crieit](https://crieit.net)にも、個人開発寄りの記事をまとめて報告しようと思っています。

## さいごに

公開するつもりでやってなかったので、コミットメッセージ分かりづらくてすみません。自分がわかればそれで良いのが、個人開発の甘えなので（笑）

一週間あれば、プロダクトはリリースできます。むしろ、アイデアからリリースまでに一週間以上かかっていたら、**遅すぎるのではないでしょうか。**とはいえ、自分がリモートワーク/フリーランスなので、一般的なスタイルではないかもです。（もちろん、日中は仕事ありますが）

この記事を読んでいただいた方が、個人開発面白いなと思ってくれたら嬉しいです！！あと、[Botcamp](http://botcamp.jp)にぜひBotやアプリを追加したり、サイトを楽しんでもられば最高です！！！

P.S.

リリース Day1から、[個人開発のフリマ](https://devmart.jp/businesses/129)でサイト丸ごと販売します。サービス開発の勉強として、あるいは、Botビジネスに興味ある人は入札してみてはいかがでしょうか？（笑）