Bubbleの実践的な使い方(要点と勘所全まとめ)

[Bubble](https://bubble.io/)とはコードを書かずにプロトタイプが作成できるNocodeツールです。
この記事ではBubbleの基本と実践的な使い方を記載いたしました。

Nocodeと言われているのでスキル獲得の参入障壁は低いかと思っていましたが、
ダッシュボードやDBの独特な取り扱い方法に苦労し、プロトタイプ作成に150時間ほど要しました笑。
初めてBubbleを触れる人でもこの記事をよれば大抵のサービスは作れるように、
要点から開発者が気になる勘所(セキュリティ、一括データ登録)まで全てまとめました。
なにか付け足す点などあればコメントいただければと思います。

最後にBubbleで作成したアプリ関する[アンケート](https://forms.gle/co2DtjevSLWyArpA9)を取らせて頂いているので
よろしければご回答お願いいたします！！


<iframe width="560" height="315" src="https://www.youtube.com/embed/MiHLZMCE3bY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# ダッシュボードの使い方
## Designページ
### Page
左上にPageという表記があり、そこで自分が修正するPage、あるいはReusable elemntsを選択する。
![スクリーンショット 2021-06-19 18.48.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/205e9453-c093-0428-7765-2f6df8c828f2.png)

### UI Builder
elementが置いてある場所。
ここにあるelementをドラッグ・アンド・ドロップすることで配置する事ができる。

#### Elements tree
現在選択しているPageやReusable elementsに配置されているelementを見える化してくれている場所。

- 黒いelementが現在Page内で見えているelement
- 灰色のelementはPopupなどの通常状態では見えていないelement
- element名の右側にある目玉アイコンを押すと、見える見えないの切り替えができる
- element名の左側にある+アイコンがあるelementはGroup elementで自身の中に複数のelementを持つ
- +アイコンを押すと、配下のelementが確認できる

![スクリーンショット 2021-06-19 18.58.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/31da335b-6c36-6e56-2dd4-d47a773bb4c9.png)

#### Visual elements
Page内に配置する非input系のelelement

#### Containers
複数のelementをGroup化するためのelement。

- Group:複数のelementを一般的にGroup化
- RepeatingGroup:Databaseのデータを一覧表示するためのGroup
- Popup:Popup用にelelementをGroup化するもの
- FloatingGroup:スクロールしても動かないelelementをGroup化するもの

#### Input forms
Page内に配置するinput系のelelement

#### Reusable element
再利用可能なelement。
ダッシュボード左上の「Page」で編集したいReusable elementを選択して修正。
使用するときはReusable elementからドラッグ・アンド・ドロップして使用する。


### Responsive
編集ページがResponsive　designになっているかを確認する。
ページ上部の灰色のバーを動かして画面幅を変更してResponsiveか確認する。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/0222e6ae-8578-fda5-95a1-f1c6f7445d2e.gif)

## Workflowページ
ここではDesignページで表示しているPageやReusable elementsにあるelementにworkflowを設定する。
workflowとは以下のような特定のトリガーを引き金にしてイベントを発生させるもの。

トリガー
- 該当のPageされたとき
- 該当のPageの該当のelementがクリックされたとき
- ユーザーがログインしたとき

イベント
- ユーザー登録、ログイン
- データ登録、変更
- Popup表示
- email送信
- 決済
- Javascript実行

「When」でトリガーを設定し、「Step」でイベントを順々に設定する
![スクリーンショット 2021-06-19 20.08.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/b2843115-b6ee-8f77-d5dd-2f6f50e439e3.png)

## Dataページ
BubbleのDataでは以下のような用語を使用する。
ここの用語をおさえていないとBubbleでのデータの操作に混乱してしまうので注意

- Type name:データベースでいうとこのテーブル名
- Field name:データベースでいうとこのテーブルのカラム名
- Field type:カラムの型
- Things:挿入されたデータ、レコードのこと

### Data types
左側で作成したテーブルの一覧を確認できる。
右側で選択しているテーブルのカラムを確認できる。
「Create a new field」で新たなカラムを設定することができる。

![スクリーンショット 2021-06-19 20.16.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/ac30de48-904b-b600-6dfc-0b017330b50b.png)

### App data
テーブルのデータをすべて確認するができる。

![スクリーンショット 2021-06-19 20.22.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/770c2d15-247b-ddf4-dc75-7939c529b989.png)

### Styles
elementに設定するstyleを設定する

### Plugins
使用したいpluginを導入して使用する
代表的なものは以下。

- Toolbox(Javascript使用する上で必要)
- Stripe(決済)
- Google Auto Ads(広告)
- ReCAPTCHA(ログイン時ロボットでないか判定するのに使用)

### Settings
基本的な設定を行う。

- App plan:  Bubbleの契約プランに関しての設定変更
- General:  SecurityやFaviconの設定
- Email/Domain:  登録するドメイン、SSL設定など
- Languages:  言語設定ではなく、アプリ内で使用する文言を設定する
- SEO:  SEO周りの設定やアプリ内で使用するJavascriptのコードを記述する場所

# Elementの設定
編集したいelementを選択して右クリックで「edit」を選択して以下のように編集する
![スクリーンショット 2021-06-19 21.17.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/ea27d442-356e-5914-2f5f-d2036211bb3c.png)


## Appearance
Appearanceタブでできることは以下

- 表示内容の記述
- Styleの設定
- WidthとHeightの設定
- Workflowの設定

## Conditional
Conditionalタブでは以下のような条件に応じた、切り替えが行える。

条件例

- ユーザーがログインしている場合
- 該当PageのCustom stateの値が任意の値の場合

切り替え例

- elementの表示をさせる、させない
- elementのstyleをstyle1にするか、style2にするか


![スクリーンショット 2021-06-19 21.25.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/c1e8e530-6125-2237-05af-e8fa3766e632.png)

### その他
トリガーによってボタンのテキストを切り替えたいときは、
一つのボタンのテキストを変更しようとするのではなく、
切り替え前のボタンと、切り替え後のボタンを用意して
各Conditionalで表示切り替えができるように設定してあげる

## Custom State
elementに設定するstateで、値を設定することができる。
この値をelementのConditionalやworkflowの条件として設定する事ができる。

### 使用用途例
以下のようなボタンを押したときにドロップダウンメニューを表示非表示を切り替える実装を行う。
![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/7c55a52a-da68-4d75-8ccb-21de6636a130.gif)


この時にindexページにisOpenというcustom stateを設定する。
これはドロップダウンメニューが開いているかいないかを判定する指標になっている。

#### isOpenがnoの状態で、ボタンが押されたとき
isOpenをyesに切り替えてドロップダウンメニューを表示するようにしている
![スクリーンショット 2021-06-19 22.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/e26023e3-3aa2-66f2-526d-b4777ef9f3e4.png)

#### isOpenがyesの状態で、ボタンが押されたとき
isOpenをnoに切り替えてドロップダウンメニューを閉じるようにしている![スクリーンショット 2021-06-20 9.18.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/e2bd1a7e-8562-c5d5-9383-833b5db5b960.png)

![スクリーンショット 2021-06-19 22.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/86c76d3c-5702-08a4-201e-f470cf9eb22e.png)

### 注意
custom stateはpageやpage内のelementに設定できるようになっているので、
別のpageのcustom stateを参照することはできない。

またcutom stateはelementの「i」というアイコンを押して表示されるElement inspectorで管理されている。
![スクリーンショット 2021-06-20 9.05.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/c8171147-6057-3878-8eef-b704a1fb04d3.png)

# HTMLのIDの設定
bubbleで配置したelelmentにHTMLのIDを設定する方法は以下になる。

- Settingページの「General」で「Expose the option to add an ID attribute to HTML elements」にチェックを入れる

![スクリーンショット 2021-06-20 13.52.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/8b9b2a0c-517f-6f33-1807-3664225d8cf2.png)

- elelmentのID Attributeに設定するIDを記述する

![スクリーンショット 2021-06-20 13.52.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/a03675fd-563c-0448-166a-9560a20121a7.png)

参考記事
[bubble.ioの汎用性を高める](https://note.com/i2vtbtwna/n/n88e1d8d7aede)


# DBの設定
テーブルのデータはそれぞれuniqueなkeyをもっており、
その値を別のテーブルが参照することで、テーブルの関係性を構築することができる。

- Userテーブル：uniqueなkeyはemail
- User以外のテーブル：uniqueなkeyはunique_id

この参照キーを変更する際は、DataタブでNew Entryしたときの「Change search field」で変更する事ができる。
![スクリーンショット 2021-06-26 13.02.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/9d0deed6-788b-1385-b81b-a8d1c552ab98.png)

![スクリーンショット 2021-06-26 13.02.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/9456411e-cf2c-6168-7b76-ffc1eca1f1bb.png)



## 1対多を実装する方法
Userが特定のPlanに入っているときの実装で再現する。
UserがPlanに従属している関係になっているので、PlanというテーブルがUserテーブルを1対多で管理している状態にする。

### 例1
UserテーブルにPlan用の外部キーカラムを作成する方法。

以下の例では、
test@test.comのUserはPlanカラムに、フリーミアムPlanのunique_idを持つことで
1対多の関係を構築している

![スクリーンショット 2021-06-20 11.03.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/6df4d4d0-e5fd-6905-43cb-8ce7241cb25b.png)

![スクリーンショット 2021-06-20 11.03.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/7ecbe22c-2da3-32fc-3c0f-e80ecb80a609.png)

### 例2
Planテーブルが、Userデータを複数もつためのUsersカラムをもつ方法

以下の例では、
フリーミアムPlanのUserカラム(配列管理できるカラム)にフリーミアムに属しているUserのemailを持つことで、
1対多の関係を構築している

![スクリーンショット 2021-06-20 11.13.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/cb0e9b76-10c6-cd98-5460-dd3aab39d789.png)

![スクリーンショット 2021-06-20 11.12.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/c56fdcc2-66ff-acd8-ecd7-17ed79771f17.png)

####List系のカラムにデータを追加する方法
以下ではプレミアムPlanのUserカラム(配列管理できるカラム)にCurrentUserの情報を追加する方法である。

![スクリーンショット 2021-06-20 14.19.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/9a3afba0-ab0a-6687-9954-1820db897f5d.png)

![スクリーンショット 2021-06-20 14.18.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/85043e28-dfca-2595-ce26-ff017d71b6b5.png)

- Make change to PlanでPlanテーブルのデータを修正するように設定
- Search for planでunique_idがプレミアムPlanのunique_idであるデータを対象にしている
- first itemを設定することで、Search for planで得られたデータのうち最初のデータのみを対象にしている
- User Add Current Userで該当のデータのUserカラムにCurrent User情報を追加している

補足
PlanテーブルのデータのいくつかにCurrent User情報を追加したい場合は、
「Make change to a list of things」を使用する

参考動画
[Bubble.io Lesson on Modifying List Fields
](https://www.youtube.com/watch?v=4BB4mZp_C3Q)

## 多対多を実装する方法
UserがどんなUserをフォローしているかを管理するFollowを使用する例を上げる。

以下の例では、
FollowテーブルのFollowingにフォローしている人のUser情報、Followedにフォローされている人のUser情報をいれて
多対多の関係を構築している

![スクリーンショット 2021-06-20 11.18.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/4b0bf709-e92c-32cb-c70f-74216027b709.png)

# ユースケース
ここから実際に様々用途に対する実装パターンを紹介する。

## 一覧表示
RepeatingGroupを使用して一覧表示したいデータを取得して表示する

- Type of content:一覧表示するデータの種類を選択
- Data source:表示するデータを設定する
- Layout style:[表示スタイル](https://manual.bubble.io/core-resources/elements/containers#layout-style)を設定

### 例1(テーブルのデータを一覧表示)
こちらの例では、MasterBooksテーブルのデータを一覧表示している
![スクリーンショット 2021-06-20 9.01.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/012e91d6-8dc9-5ded-637f-6c6ce7d8a3ab.png)

### 例2(1対多の関係での一覧表示)
こちらの例ではこのページに渡されてきたMaterBookのデータが持つwordsというデータを表示している
![スクリーンショット 2021-06-20 9.13.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/092225e0-b264-5089-8d67-973e78c2d145.png)

これを行うためには以下のような設定が必要である。
#### テーブル構成
MasterBookテーブルがWordテーブルのデータをListで持つような1対多の関係になっていなければいけない
![スクリーンショット 2021-06-20 9.18.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/44e5c057-1562-eeb3-7576-8819a6188545.png)

#### 前のPageから該当のMasterBookデータが送られてきていないといけない
![スクリーンショット 2021-06-20 9.27.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/81e63fa9-daff-489a-5324-9c82621d8369.png)

### 例3(多対多のフォロー機能)
こちらの例では自分フォローをしているUserを表示している

こちらの例ではログインしているCurrentUserがフォローしているUserのemailを一覧表示するようにしている
![スクリーンショット 2021-06-20 11.32.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/641d71c0-4b5c-b8f0-3094-f252ccd3917c.png)

これを行うためには以下のような設定が必要である。
#### テーブル構成
先程も紹介したように、
FollowテーブルのFollowingにフォローしている人のUser情報、Followedにフォローされている人のUser情報をいれて
多対多の関係を構築している

![スクリーンショット 2021-06-20 11.18.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/4b0bf709-e92c-32cb-c70f-74216027b709.png)

### 例4(より複雑なテーブル構成、多対多対多)
以下のような複雑なテーブル構成を構築する場合。

> 
Userが複数のWordBook(単語帳)を登録することができ、
WordBookは複数のWord(単語)も持つことができる。
Wordは一つのWordBookのみから参照されるわけではなく、複数のWordBookから参照される。

#### Bubbleでは動かないDB構成
UserとWordBookが多対多になっていて、WordBookとWordが多対多になっているケースなので、
通常のDBでは以下のようなテーブル構成になりがち。

![スクリーンショット 2021-06-21 20.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/d6f1c6fe-8e17-0676-70e3-52997d0a65bf.png)

しかしこの場合Bubbleで、特定のUserが持つ複数のWordBookに含まれるWordをすべてを得る
ということができない。

#### Bubbleで動くDB構成

![スクリーンショット 2021-06-21 20.21.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/a33eda0f-9260-24c7-a104-2fdb6a6c84da.png)

このような構成にすると、以下のような方法で
特定のUserが持つ複数のWordBookに含まれるWordをすべてを得る事ができる。

![スクリーンショット 2021-06-21 20.28.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/3cd329b5-0051-087a-02fc-086db72979d3.png)


## 検索
こちらも一覧表示の応用になっている

![スクリーンショット 2021-06-20 9.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/5d864bb3-9d21-acf3-6af4-709abdee179b.png)

上記の例では

- Wordデータの表示
- 表示するWordの条件として、「WordのEnglishカラムに、検索インプットelementで記述された内容を含む」を設定


より高速な検索Fuzzy searchの方法は以下が参考になる
[Fast Fuzzy Search | Bubble.io Tutorial
](https://www.youtube.com/watch?v=yiMqvbeYvT0)

## Javascript

### 実行方法
前提として以下が必要

- [ToolBox](https://bubble.io/plugin/toolbox-1488796042609x768734193128308700)というPluginの導入
- プレミアムプランへの加入

その後workflowでPluginsで「run javascript」を選択する
![スクリーンショット 2021-06-20 11.56.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/8a63de3e-ebb7-a389-a881-8acde22c5fc5.png)

custom_methodという独自のメソッドを使用する
![スクリーンショット 2021-06-20 11.59.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/390d0a84-7289-51ca-a8c3-e9f986a35bec.png)

独自メソッドの定義はSettingページの「SEO/metatags」で行う
![スクリーンショット 2021-06-20 12.03.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/244f2b0f-3ee8-ec64-fe0e-1be8d21e4b07.png)

参考の動画はこちら
[Bubble.is: Run Javascript Dynamically](https://www.youtube.com/watch?v=Qo6YPhqfoJ4)

#### 注意
Javascriptでもbubble内のDynamic dataを使用することができる。

![スクリーンショット 2021-06-20 14.41.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/82e60c09-aa19-06b8-d2e1-5a0ad7e4247e.png)

上記のようにbubbleのString、int、listデータを扱える。
しかしbubbleで使用されているlistデータはjavascriptで扱う場合は注意が必要

##### だめな例
「Run Javascript」のコード内で直接bubbleのlistデータを変数にセットするパターン。

「Current User's WordBooks's Words's content」が配列のデータとなっており、その値と直接Jsの変数に格納している
![スクリーンショット 2021-07-04 10.32.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/9373abf1-b5e0-0bd5-d03a-ee0ab7c9b542.png)

この状態でJsを走らせると以下のようなエラーが発生する。
![スクリーンショット 2021-07-04 10.27.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/2e537959-f05c-e248-52de-98124a570ff1.png)

原因はbubbleの配列データの形式と、Javascriptの配列データの形式が異なるため。

##### 良い例
bubbleのlistデータを一度JavascriptのStringに変換してから、配列に変換する。

まずbubbleのlistデータを「""」で囲むことで、JavascriptのStringに変換する
![スクリーンショット 2021-07-04 10.42.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/a004b824-0830-2e21-44dd-f874701fa120.png)

この値は以下のような形式のデータになる。
![スクリーンショット 2021-07-04 10.37.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/e479c728-6a42-c5c7-d1f3-de93467316de.png)

つぎにStringデータをListデータに変換する。
Stringデータは、要素と要素が「, 」で区切られているので、「, 」で切り分けるようにする。
![スクリーンショット 2021-07-04 10.46.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/0f1fc910-167d-7e6e-f5ea-f4f3c2c92c1c.png)

これでJavascriptで扱える配列が定義できる
![スクリーンショット 2021-07-04 10.47.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/00f595e8-1db0-82a3-f294-235b69e34394.png)



参考記事
[How to transform Bubble list into a Javascript Array](https://forum.bubble.io/t/how-to-transform-bubble-list-into-a-javascript-array/145603)


### Javascriptの変数をbubbleで扱えるようにする方法
Javascript to bubbleというelementを使用する

以下のような打ち込まれたtextをJavascriptで読み取って、
その値をjavascript to bubbleに渡してtextに表示する例を参考にする

![ezgif.com-gif-maker (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/69b6cb05-5a89-7343-5ce6-8f976c99beff.gif)

- input formにyournameというidを設定
![スクリーンショット 2021-06-20 15.22.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/ddfeb22f-903b-01e1-d15f-ac12368caef9.png)

- Read input into bubbleボタンのclickイベントに以下を設定する
yournameを取り出して、bubble_fn_readinoutに入れる
![スクリーンショット 2021-06-20 15.24.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/9f97ea6e-6926-ae0b-8154-75290985971d.png)

- Javascript to bubbleの設定
bubble_fn_suffixを「readinput」にして、
publish valueにチェックを入れることで、
bubble_fn_readinoutの引数に設定された値をこのJavascript to bubbleの値として設定する
![スクリーンショット 2021-06-20 15.26.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/95d0998c-74b4-93c2-ad56-0bc34882f537.png)

- textでJavascript to bubbleの値を表示する
![スクリーンショット 2021-06-20 15.28.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/7a99cccd-3ece-0067-a12c-db1ec44d1c21.png)


参考記事、動画

- [How to save input from html element using javascript to bubble](https://forum.bubble.io/t/how-to-save-input-from-html-element-using-javascript-to-bubble/47568/4)
- [Using Toolbox (Run Javacript) and JavaScript to Bubble Elements in Bubble](https://vimeo.com/278023158)

#### 注意
Javascript to bubbleの値を変更するeventとそのJavascript to bubbleの値を使用したデータの変更eventを同じworkflow内にかくと、データの変更が実行されない

そのためJavascript　to bubbleを用いたデータ変更は以下のように行う

![スクリーンショット 2021-06-20 15.46.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/a569e995-942a-7f8f-d4b0-c15db9f7d2b7.png)

![スクリーンショット 2021-06-20 15.47.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/700e2860-90af-d622-de3a-1f839dbe6977.png)

Javascript to bubble eventでJavascript to bubbleの値の変更を検知して、データを変更を駆動するようにする。

そのときに、Javascript to bubbleのtrigger eventにチェックを入れることを忘れずに！

![スクリーンショット 2021-06-21 22.57.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/e34d3d04-b07f-a873-fc28-d41f8a3aa323.png)


## ユーザー新規登録・ログイン
ユーザー新規登録・ログインの説明を行うと、それだけでもかなり内容が多くなるので参考動画の記載だけさせていただきます。

参考動画
[Bubbleの使い方 - Part 7 - ユーザー登録・ログイン処理](https://www.youtube.com/watch?v=LRGWVGwmZYE&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=9)

### メアド認証
ユーザーの新規登録時に登録メールアドレスに認証メールを送信して、認証リンクがクリックされたかを確認する方法

#### 登録メールアドレスに認証メールを送信する方法
ユーザー登録ボタンが押されたときのworkflowのSign the user upを以下用に設定する

- Send an email to confirm the emailをチェックする
- Confirmation pageに認証リンクが押されたときのページを設定する

![スクリーンショット 2021-06-20 17.51.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/02e570cd-94e8-d2ef-eaff-c35bafee3f3a.png)

#### 認証リンクがクリックされたかを確認する方法
workflowのwhenで以下のように確認する
![スクリーンショット 2021-06-20 17.55.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/3a9b77ef-a932-e2ad-130e-5af8a83c0bdb.png)

参考記事
[Send confirmation email action](https://forum.bubble.io/t/send-confirmation-email-action/34627)

## 決済
決済に関しては、それだけでかなり内容が多くなるので参考の記事を掲載だけしておきます。

参考記事

- [Bubble での Stripe を使ったクレジットカード決済の始め方](https://blog.nocodelab.jp/entry/stripe)
- [Add Subscription Payments with Stripe to Bubble.io App](https://www.youtube.com/watch?v=UEN6L2JRPLo)

### 注意点
決済のテストを行う場合は、テスト用のクレジットカード番号を入れるようにする

参考記事

- [基本的なテストカード番号](https://stripe.com/docs/testing#cards)
- [Stripe決済テストに役立つダミーカード番号、ステータスコードまとめ](https://biz.addisteria.com/stripe_test_dummy/)

## Google sheetを使用したデータ入力
一度に多くのデータをbubbleへ入力するためにGoogle sheetと[integromat](https://www.integromat.com/en/features)を使用する。
integromatではGoogle sheetの内容を読み取り、そのデータをbubbleに送信しデータ登録をさせることに使用する。

その他にもGoogle Sheetからbubbleへのデータ入力を行えるツールは存在する。

- [integromat](https://www.integromat.com/en/features)
- [zapier](https://zapier.com/how-it-works)
- [pabbly](https://www.pabbly.com/)

参考動画・記事

- [integromat](https://www.youtube.com/watch?v=j8CrvOG5fiY)
- [zapier](https://www.youtube.com/watch?v=73ajoZRXNqc)
- [pabbly](https://www.pabbly.com/connect-google-sheets-to-bubble-apps/)

今回integromatを選択した理由は、zapierではGoogle sheetの複数レコードを一度に登録することができず、integromatではそれができたため。
pabblyは使用していないのでわからない。

### 実践方法
#### 準備
以下のDocumentを参考して、integromatから接続を確認するためのMytableを作成とbubble APIの公開を行う
[Bubble Getting started with Bubble](https://www.integromat.com/en/help/app/bubble)

#### Google sheetの設定
1行目に代入したい値のkey名を設定して、2行目移行に実際のvalueを記入する
![スクリーンショット 2021-06-27 11.03.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/22a96782-321a-5a8e-5bd6-f203eab8f5d5.png)

その後にintegromatがGoogle sheetにアクセスできるように、Google sheetにintegromatのpluginをインストールして設定を行う。
こちらの手順も多いので公式のDocumentだけ以下に参照しておく
[Google Sheets](https://www.integromat.com/en/help/app/google-sheets)

#### integromatの設定
integromatが公式に紹介しているGoogle sheetからbubbleの統合をやり方を実践する。
[こちら](https://www.integromat.com/en/integrations/bubble)の「Import spreadsheet data into bubble」のやり方で行う。
![スクリーンショット 2021-06-27 11.13.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/677bf215-f351-9e12-3cc3-779b2a294f7d.png)

##### Google Sheet
以下を設定する

- 連携させるGoogleアカウント
- spreadsheetの選択
- sheetの選択
- sheet内の範囲選択
- sheetのどの部分がデータのkeyに当たる部分かを設定
- 一度にデータ登録する数の上限値

![スクリーンショット 2021-06-27 11.28.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/8d7896b4-da29-2294-abdc-53309ae5bc38.png)


![スクリーンショット 2021-06-27 11.16.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/ef3687f8-7b24-2f32-b78a-2d6afd91f4d7.png)

##### bubble

Connectionで連携させるbubbleアプリを設定する。
具体的な方法は以下を参考にする。
[Bubble Getting started with Bubble](https://www.integromat.com/en/help/app/bubble)

![スクリーンショット 2021-06-27 11.20.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/003215a2-90b5-47c6-b83a-536e742db79a.png)

Typenameでデータ入力するテーブルを選択
![スクリーンショット 2021-06-27 11.23.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/4ae7280b-226c-4d93-8530-5664ac521fd9.png)

Entry fieldsで入力するデータの設定を行う

- Field Nameで入力されるテーブルのカラム
- Typeで型指定
- ValueでGoogle　sheetのどの列の値をデータ入力するか設定

![スクリーンショット 2021-06-27 11.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/5ef60822-c94b-3ca8-0ff0-8118a88b694d.png)

### 注意
#### unique_idの値の設定はできない
Field Nameにunique_idを設定してunique_idの値を設定することはできない。
なので外部から参照されるようなデータを入力するときは参照用のIDも設定すると良い。

以下の例ではWordというデータにreference_id（外部から参照されるようのID）を設定してデータ登録をしている。
Wordのデータ参照はunique_idではなく、reference_idにすることで、参照しているデータへの入力も用意になる。

![スクリーンショット 2021-06-27 11.03.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/22a96782-321a-5a8e-5bd6-f203eab8f5d5.png)

![スクリーンショット 2021-06-27 11.42.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/6c2ee5a4-971f-0145-d65e-672785ff1177.png)

![スクリーンショット 2021-06-27 11.42.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/bf6b9f7f-dcda-4e23-587f-88383bc870db.png)

![スクリーンショット 2021-06-27 11.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/b124fb19-f9f3-3bd5-685e-b8f3a9c5d59f.png)

#### 外部テーブルを参照しているカラムにはデータ登録できない。
Bubbleのテーブルが型に設定されているカラム(外部キーを参照しているカラム)にはデータ登録することはできない。
例えばWordBookというテーブルでは、Wordsというカラムで、先程見たWordを複数、Listで保持できるようになっている。

![スクリーンショット 2021-06-27 11.47.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/b029b241-8960-032b-254a-d5021b493c00.png)

しかしこのWordsカラムはBubbleのテーブルが型に設定されているため、integromatでデータ登録することができない(おそらく他のToolでも不可能)。
たとえ先程行ったように、Wordのデータ参照はunique_idではなく、reference_idに設定してもデータ登録はできるようにならない。

![スクリーンショット 2021-06-27 11.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/b124fb19-f9f3-3bd5-685e-b8f3a9c5d59f.png)

なので他のテーブルを参照しているデータに、手入力で入力する必要がある模様。

![スクリーンショット 2021-06-27 11.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/0347f9cf-3c37-8e80-b1f3-53306ac0eaf1.png)

#### 大量のデータ登録
大量のデータ(1000行を超えたあたり)を登録するには課金がひつようになる。

#デザイン
レスポンシブを実装する上でのTipsを紹介する

##固定されたelementを実装する
![ezgif.com-gif-maker (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/0c0b56f1-9ad9-a291-1701-9fe9d43647d5.gif)


Floating groupに固定したいelementを入れる
![スクリーンショット 2021-06-20 18.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/7e508e37-4a37-27f3-a024-c2134fdb8a5b.png)

参考記事
[Position fixed, regardless of scroll](https://forum.bubble.io/t/position-fixed-regardless-of-scroll/30225/2?u=tsuyozo7)

## Fixed width

elementのwidthを画面幅変わっても固定にするのか、画面幅が狭くなれば縮小させるのかをFixed widthで設定する

###Fixed widthの場合
ボタンの幅を固定にする
![スクリーンショット 2021-06-20 18.23.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/abc55864-93c5-063d-d304-090659d71229.png)

画面幅が縮小してもボタンの幅は変わらないようになっている
![ezgif.com-gif-maker (4).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/4778a24c-0f18-03bc-4b16-8ecfd0a17a1f.gif)

### Fixed width出ない場合
ボタンの幅を画面幅に合わせて縮小させる。

![スクリーンショット 2021-06-20 18.39.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/51693175-f399-8a9c-2b72-5a28fae68bfe.png)

- Current minimum width
最低でも最大最大widthの50%の幅は確保するように設定

- Apply a max width
最大widthを設定する

- Collapse margins when container width
自分の親のGroupの大きさがどれだけ小さくなったときに、このelelmentのmarginを0にするか

画面幅に合わせてボタンの幅が縮小している
![ezgif.com-gif-maker (5).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/6a498b28-c4b5-47ac-3f4a-ecae7b8d5922.gif)

参考動画
[Bubbleの使い方 - Part 3 - レスポンシブデザインについて
](https://www.youtube.com/watch?v=y5OLDgFvgTY&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=4&t=295s)

## 横並びのelementを画面縮小時にも横並びにする
上記のFixed widthの項目で確認したように、
通常、横並びのelementは画面が縮小されると縦並びになるように変更される。

縮小されても横並びの関係性を保つためにShapeを設置する
![スクリーンショット 2021-06-20 18.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/c2183792-f385-36be-126d-de6ae36bfd54.png)

灰色のShapeBを配置することで、縮小されても縦並びになるようになる
![ezgif.com-gif-maker (6).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/a00de8ee-d08e-0a05-4497-14801fbcf679.gif)

# セキュリティー
bubbleが公式にsecurityとprivacyに関して説明した動画で以下のような発言をしている
[Security & Privacy](https://bubble.io/video-course/security--privacy-1600816591920x608075716417290200?utm_source=blog&utm_medium=link&utm_campaign=web-app)

> bubble provides you with state of the art security.

> We encrypt all traffic to Bubble.io over HTTPS (the green padlock on your address bar) and automatically pass through Cloudflare for domains to help worldwide accessibility and Distributed Denial of Service Protection (DDoS). 

> bubble gives you user authentication of the box. but the user data type only stores email.
All user passwords are stored salted and encrypted in our database.
this means that no one has access to your password not even the owner of the application.

> You can control who accesses your data with Privacy Rules. You can set conditions for who can view, modify, search, or delete items of a certain data type.

内容としては、bubbleでは以下のような対応をしているので最大限のセキュリティーの考慮をしているとのこと

- httpをsslで通信
- ユーザ情報を保存するときにパスワードの管理はハッシュ化と暗号化されてbubble側で管理されているので、アプリ管理者さえ知ることができない
- データへのアクセスのコントロールをprivacy ruleで設定できる

主に開発者が対応するべきセキュリティーの内容に関しては、
[airdev](https://airdev.co/)というbubbleをleadしてる会社が提示してくれている。
[Secure your app](https://docs.airdev.co/bubble-development-guide/steps/develop/secure-your-app)

## 主な脆弱性に対する対応
### XSS
bubbleのfounderのJoshua Haasさんが、HTML用のelementに関してはXSSの対応が必要だが、
その他の通常のbubbleのelementはXSSの対策がされていると発言されている。
[Cross-site Scripting Vulnerabilities](https://forum.bubble.io/t/cross-site-scripting-vulnerabilities/3004/2)

> -If you use an HTML element, be very careful where that HTML comes from… if it comes from user-edited data, you have a potential cross-site scripting vulnerability. Generally, if you’re using the HTML element, you should be controlling the source of the HTML very carefully.

> -However, other built-in Bubble elements should not vulnerable to cross-site scripting attacks.

### CSRF
以下の例でCSRFトークンを取得しないとAPIを呼び出したときに403のエラーが発生してしまうと記述があるので、
CSRFの対応もしっかり行われていると思われる
[Getting API working with API Connector](https://forum.bubble.io/t/getting-api-working-with-api-connector/93470/5)

> I can tell you what might lead to a solution - I need to get a CSRF token to start. The rest of the calls return a 403 which indicates that my first call to get the token didn’t go through.

### SQL Injection
以下の例でbubbleサポートの回答で、SQLインジェクション対応を行っていることに関して話題に挙げています。
[Preventing SQL Injection in Bubble + WYSIWYG Plugin](https://forum.bubble.io/t/preventing-sql-injection-in-bubble-wysiwyg-plugin/22860/4)

> We use Postgres’ query-escaping mechanism to safely send parameters to queries to avoid SQL injection attacks. 

## Privacy rules
特定のデータに関して閲覧・編集権限などを制限するためにprivacy rulesを設定する。

![スクリーンショット 2021-06-25 22.11.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/eee420f1-5de9-c761-8409-053369d52441.png)

- DataページのPrivacyで各テーブルに設定可能
- Nameでルールの名前を設定
- Whenでどんな条件の場合かを設定
- Users who match this rule canで権限の設定
- Everyone elseとはNameで設定したルール条件以外の場合
(こちらの例ではThis User is Current User以外の場合)

### 権限内容

- View all fieldでどのfieldがみれるか
- Find this in searchesでこのデータを探すことができるか
- View attached fileでこのデータに添付されたファイル(画像ファイルなど)をみることができるか？
- Allow auto-bindingでこのデータのfieldを変更できるか


参考動画・記事

- [How to Setup Privacy Rules | Bubble Tutorial](https://www.youtube.com/watch?v=1-meIeBUXPY)
- [Privacy](https://manual.bubble.io/core-resources/data/privacy)

## Encryption
機密性の高いデータに関しては暗号化することを推薦されているため、Encryption対応を行う。

参考動画
[How To Encrypt & Secure Sensitive Data in Bubble.io](https://www.youtube.com/watch?v=l3e0EmmVZX0)

### 補足
bubbleサポートによると現状ではUserテーブルのemailカラムを暗号化することはできないので、
privacy ruleを設定して権限のないユーザーには見せない用に設定することが推薦されている。
[Encrypting the created by email](https://forum.bubble.io/t/encrypting-the-created-by-email/66655/3)

> Unfortunately, there is no way to encrypt a user’s email address within the datatable for Bubble itself.

> If you’re worried about someone figuring out who a report was created by in the Bubble database, you can set privacy rules 2 to ensure that a user cannot see the email address associated with a report unless they are authorized to do so.

# Tipsやその他

##重なったelementの切り替え
重なったelementを切り替える場合は「command」を押しながらelelmentをクリックすると切り替わる。

![ezgif.com-gif-maker (7).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510817/365f46aa-ca29-0931-e3d2-9d535ece9b0d.gif)

## デプロイ
参考動画
[Bubbleの使い方 - Part 11 - 本番サイト公開](https://www.youtube.com/watch?v=md2wnfuVRGg&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=12&t=116s)

## デバッグ・バージョン管理
参考動画
[Bubbleの使い方 - Part 1.5 - 学んでいくことの確認とデバッグ、バージョン管理方法](https://www.youtube.com/watch?v=m7knbYDM_Ow&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=2)

## 複数のデータの一斉操作
参考動画
[Bulk Operations: How To Edit Large Lists of Data - Bubble.io Tutorial](https://www.youtube.com/watch?v=d8BucVYOI24)

# 成果物・アンケート

## 成果物
今回bubbleを使用して作成したものは英単語を聞き流して覚えれるアプリです。

- 英単語帳に複数の英単語が登録されている(約300単語)
- 聞き流ししたい英単語帳を設定
- 聞き流しを開始すると、英単語帳に登録されている英単語の発音と意味を順番に聞き流すことができる


詳しい機能や使い方は以下の動画でを説明させていただきました。
画質は720pまであげてご確認ください！
<iframe width="560" height="315" src="https://www.youtube.com/embed/MiHLZMCE3bY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## アンケート
以下で上記の聞き流し英単語のアンケートを取らせて頂いていますので、よろしければご回答お願いいたします！！
[アンケート](https://forms.gle/co2DtjevSLWyArpA9)

# 参考文献

## メイン
- [Uber風のサイト構築を通して学ぶ、Bubbleの使い方](https://www.youtube.com/playlist?list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj)
- [ノーコードツール【 Bubble 】を使ってツイッターを作ろう！（基礎をしっかり学べます）](https://www.udemy.com/course/bubble-u/)
- [Bubble での Stripe を使ったクレジットカード決済の始め方](https://blog.nocodelab.jp/entry/stripe)

## サブ

- [bubble.ioの汎用性を高める](https://note.com/i2vtbtwna/n/n88e1d8d7aede)
- [Bubble.io Lesson on Modifying List Fields
](https://www.youtube.com/watch?v=4BB4mZp_C3Q)
- [Fast Fuzzy Search | Bubble.io Tutorial
](https://www.youtube.com/watch?v=yiMqvbeYvT0)
- [Bubble.is: Run Javascript Dynamically](https://www.youtube.com/watch?v=Qo6YPhqfoJ4)
- [How to transform Bubble list into a Javascript Array](https://forum.bubble.io/t/how-to-transform-bubble-list-into-a-javascript-array/145603)
- [How to save input from html element using javascript to bubble](https://forum.bubble.io/t/how-to-save-input-from-html-element-using-javascript-to-bubble/47568/4)
- [Using Toolbox (Run Javacript) and JavaScript to Bubble Elements in Bubble](https://vimeo.com/278023158)
- [Bubbleの使い方 - Part 7 - ユーザー登録・ログイン処理](https://www.youtube.com/watch?v=LRGWVGwmZYE&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=9)
- [Send confirmation email action](https://forum.bubble.io/t/send-confirmation-email-action/34627)
- [基本的なテストカード番号](https://stripe.com/docs/testing#cards)
- [Stripe決済テストに役立つダミーカード番号、ステータスコードまとめ](https://biz.addisteria.com/stripe_test_dummy/)
- [Add Subscription Payments with Stripe to Bubble.io App](https://www.youtube.com/watch?v=UEN6L2JRPLo)
- [Position fixed, regardless of scroll](https://forum.bubble.io/t/position-fixed-regardless-of-scroll/30225/2?u=tsuyozo7)
- [Bubbleの使い方 - Part 3 - レスポンシブデザインについて
](https://www.youtube.com/watch?v=y5OLDgFvgTY&list=PLiDMHhMXhuXRfwx-sRoBCrClO5V6sEclj&index=4&t=295s)
- [Security & Privacy](https://bubble.io/video-course/security--privacy-1600816591920x608075716417290200?utm_source=blog&utm_medium=link&utm_campaign=web-app)
- [Secure your app](https://docs.airdev.co/bubble-development-guide/steps/develop/secure-your-app)
- [Cross-site Scripting Vulnerabilities](https://forum.bubble.io/t/cross-site-scripting-vulnerabilities/3004/2)
- [Getting API working with API Connector](https://forum.bubble.io/t/getting-api-working-with-api-connector/93470/5)
- [Preventing SQL Injection in Bubble + WYSIWYG Plugin](https://forum.bubble.io/t/preventing-sql-injection-in-bubble-wysiwyg-plugin/22860/4)
- [How to Setup Privacy Rules | Bubble Tutorial](https://www.youtube.com/watch?v=1-meIeBUXPY)
- [Privacy](https://manual.bubble.io/core-resources/data/privacy)
- [How To Encrypt & Secure Sensitive Data in Bubble.io](https://www.youtube.com/watch?v=l3e0EmmVZX0)
- [Bulk Operations: How To Edit Large Lists of Data - Bubble.io Tutorial](https://www.youtube.com/watch?v=d8BucVYOI24)
- [integromat](https://www.integromat.com/en/features)
- [zapier](https://zapier.com/how-it-works)
- [pabbly](https://www.pabbly.com/)
- [integromat](https://www.youtube.com/watch?v=j8CrvOG5fiY)
- [zapier](https://www.youtube.com/watch?v=73ajoZRXNqc)
- [pabbly](https://www.pabbly.com/connect-google-sheets-to-bubble-apps/)
- [Google Sheets](https://www.integromat.com/en/help/app/google-sheets)
- [Bubble integrations](https://www.integromat.com/en/integrations/bubble)
- [Bubble Getting started with Bubble](https://www.integromat.com/en/help/app/bubble)