【プロフィール保存】users/{uid} にdisplayName・email・departmentを保存する
このページでやること
このページでは、新規登録したユーザーのプロフィールをFirestoreに保存します。
Firestoreとは、Firebaseのデータベースです。
データベースとは、アプリの情報を保存する場所です。
前のページでは、Firebase Authenticationにアカウントを作成しました。
今回は、そのユーザーの名前・メールアドレス・所属を、Firestoreの users/{uid} に保存します。
Firebase Authentication
↓
ログイン用アカウントを作る
Cloud Firestore
↓
アプリ内で使うプロフィールを保存する
今日のゴール
新規登録ボタンを押したときに、次の流れで動くようにします。
名前を入力する
↓
所属を入力する
↓
メールアドレスを入力する
↓
パスワードを入力する
↓
Firebase Authenticationにユーザーを作成する
↓
uidを取得する
↓
Firestoreの users/{uid} にプロフィールを保存する
保存するデータは、次の内容です。
| 保存する項目 | 一言説明 |
|---|---|
displayName | 画面に表示する名前 |
email | ログインに使うメールアドレス |
department | 所属・部署・チーム名 |
photoUrl | プロフィール画像URL。今回は空文字 |
defaultRole | 初期の権限。今回は member |
createdAt | 作成日時 |
updatedAt | 更新日時 |
uid とは、Firebase Authenticationがユーザーごとに発行するIDです。
npmや環境変数はこのページで必要?
このページでは、npmは使いません。
環境変数も設定しません。
このページで必要なのは、すでに追加したこの2つです。
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
firebase_auth はログイン・新規登録に使います。
cloud_firestore はFirestoreにデータを保存するために使います。
Step 1:Firebase ConsoleでFirestoreを有効にする
まだFirestoreを作っていない場合は、Firebase Consoleで有効にします。
Firebase Consoleを開きます。
https://console.firebase.google.com/
次の流れで進めます。
Firebase Console
↓
Firestore Database
↓
データベースを作成
↓
テストモードで開始
↓
ロケーションを選択
↓
有効化
テストモードとは、開発中に読み書きしやすい設定です。
本番公開では、安全なSecurity Rulesに変更します。
本番公開とは、実際のユーザーにアプリを使ってもらう状態のことです。
Step 2:main.dartを開く
Flutterプロジェクトの中で、次のファイルを開きます。
lib/main.dart
VS Codeを使っている場合は、ターミナルで次を実行してもOKです。
code lib/main.dart
code が使えない場合は、VS Codeの左側から lib/main.dart を開いてください。
Step 3:Firestoreのimportを確認する
main.dart の上の方に、次の1行があるか確認します。
import 'package:cloud_firestore/cloud_firestore.dart';
この1行がないと、FirebaseFirestore が使えません。
FirebaseFirestore とは、FlutterからFirestoreを操作するための入口です。
もしなければ、追加してください。
完成コードの上部は、だいたい次のようになります。
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';
Step 4:今のregister()を探す
RegisterPage の中にある register() を探します。
前のページでは、次のような処理を書きました。
final credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password,
);
final user = credential.user;
if (user == null) {
setState(() {
errorText = 'ユーザー作成に失敗しました。';
});
return;
}
if (mounted) {
Navigator.of(context).pop();
}
このままだと、Authenticationにユーザーは作れますが、Firestoreにプロフィールは保存されません。
今回は、この間にFirestore保存処理を追加します。
Step 5:register()を差し替える
RegisterPage の register() を、次のコードに置き換えてください。
Future<void> register() async {
setState(() {
isLoading = true;
errorText = null;
});
final displayName = displayNameController.text.trim();
final department = departmentController.text.trim();
final email = emailController.text.trim();
final password = passwordController.text;
if (displayName.isEmpty ||
department.isEmpty ||
email.isEmpty ||
password.isEmpty) {
setState(() {
isLoading = false;
errorText = 'すべての項目を入力してください。';
});
return;
}
try {
final credential =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password,
);
final user = credential.user;
if (user == null) {
setState(() {
errorText = 'ユーザー作成に失敗しました。';
});
return;
}
await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'displayName': displayName,
'email': email,
'department': department,
'photoUrl': '',
'defaultRole': 'member',
'createdAt': FieldValue.serverTimestamp(),
'updatedAt': FieldValue.serverTimestamp(),
});
if (mounted) {
Navigator.of(context).pop();
}
} on FirebaseAuthException catch (e) {
setState(() {
errorText = e.message ?? '新規登録に失敗しました。';
});
} on FirebaseException catch (e) {
setState(() {
errorText = e.message ?? 'プロフィール保存に失敗しました。';
});
} catch (_) {
setState(() {
errorText = '新規登録に失敗しました。';
});
} finally {
if (mounted) {
setState(() {
isLoading = false;
});
}
}
}
これで、Authenticationにユーザーを作ったあと、Firestoreにもプロフィールを保存できます。
Step 6:Firestore保存部分だけ見る
今回追加した中心部分はここです。
await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'displayName': displayName,
'email': email,
'department': department,
'photoUrl': '',
'defaultRole': 'member',
'createdAt': FieldValue.serverTimestamp(),
'updatedAt': FieldValue.serverTimestamp(),
});
短く言うと、こういう意味です。
usersコレクションを選ぶ
↓
user.uidをドキュメントIDにする
↓
名前・メール・所属を保存する
collection は、Firestoreのコレクションを選ぶ命令です。
コレクションとは、同じ種類のデータをまとめる箱です。
doc は、ドキュメントを指定する命令です。
ドキュメントとは、1件分のデータです。
set は、データを保存する命令です。
Step 7:users/{uid} の意味
今回の保存先は、次の形です。
users/{uid}
たとえば、Firebase Authenticationで作られた uid が abc123 だった場合、保存先はこうなります。
users/abc123
この中に、プロフィールを保存します。
users/abc123
displayName: 山田太郎
email: test@example.com
department: 開発チーム
photoUrl:
defaultRole: member
createdAt: 作成日時
updatedAt: 更新日時
uid をドキュメントIDにすると、AuthenticationのユーザーとFirestoreのプロフィールを結びつけやすくなります。
Step 8:FieldValue.serverTimestamp()とは何か
この部分を見ます。
'createdAt': FieldValue.serverTimestamp(),
'updatedAt': FieldValue.serverTimestamp(),
FieldValue.serverTimestamp() は、Firestore側の現在時刻を保存する命令です。
現在時刻とは、データを保存した日時のことです。
スマホやパソコンの時計ではなく、Firestore側の時刻を使います。
そのため、ユーザーの端末の時計が少しズレていても、保存時刻をそろえやすくなります。
createdAt
↓
最初に作成した日時
updatedAt
↓
最後に更新した日時
今回は新規作成なので、両方に同じタイミングの時刻を入れます。
Step 9:FirebaseExceptionを追加した理由
今回のコードには、次の部分があります。
} on FirebaseException catch (e) {
setState(() {
errorText = e.message ?? 'プロフィール保存に失敗しました。';
});
}
FirebaseException は、FirestoreなどFirebase全体で起きるエラーです。
Authenticationのエラーは FirebaseAuthException。
Firestoreのエラーは FirebaseException として受け取ることが多いです。
たとえば、FirestoreのRulesで拒否された場合などにエラーになります。
Rulesとは、誰がデータを読めるか・書けるかを決める設定です。
Step 10:保存する
main.dart を保存します。
Macの場合:
command + S
Windowsの場合:
Ctrl + S
Step 11:実行する
ターミナルで実行します。
flutter run
すでに起動している場合は、ターミナルで r を押します。
r
画面構成やFirebase処理を変えたあとに動きがおかしい場合は、R でホットリスタートしてください。
R
r はホットリロードです。
R はホットリスタートです。
ホットリスタートとは、アプリの状態をリセットして起動し直す機能です。
Step 12:新規登録を試す
ログイン画面から、次を押します。
新規登録はこちら
新規登録画面で、次のように入力します。
名前:山田太郎
所属:開発チーム
メールアドレス:test2@example.com
パスワード:password123
前のページで test@example.com を使った場合は、別のメールアドレスを使ってください。
同じメールアドレスを使うと、すでに登録済みのエラーになります。
入力したら、新規登録ボタンを押します。
新規登録
Step 13:Authenticationで確認する
Firebase Consoleを開きます。
https://console.firebase.google.com/
次の場所を見ます。
Authentication
↓
Users
登録したメールアドレスがあればOKです。
test2@example.com
Step 14:Firestoreで確認する
次に、Firestoreを開きます。
Firestore Database
↓
データ
↓
users
users コレクションの中に、ユーザーの uid がドキュメントIDとして作られていれば成功です。
中身に次の項目があるか確認します。
displayName
email
department
photoUrl
defaultRole
createdAt
updatedAt
ここまで確認できたら、このページのゴール達成です。
うまくいった状態
成功すると、Firebase側は次のようになります。
Authentication
└ test2@example.com が作成される
Firestore
└ users
└ uid
├ displayName
├ email
├ department
├ photoUrl
├ defaultRole
├ createdAt
└ updatedAt
このように、ログイン用アカウントとプロフィール情報を分けて保存します。
よくあるエラーと直し方
| エラー | 原因 | 直し方 |
|---|---|---|
FirebaseFirestore isn't defined | importがない | cloud_firestore.dart をimportする |
FieldValue isn't defined | importがない | cloud_firestore.dart をimportする |
permission-denied | Firestore Rulesで拒否されている | 開発用Rulesを確認する |
email-already-in-use | メールが登録済み | 別のメールを使う |
operation-not-allowed | Email/Passwordが無効 | Authenticationで有効にする |
| Firestoreにusersが出ない | 保存処理が動いていない | set() の位置を確認する |
| 画面が変わらない | 保存していない | command + S |
permission-denied** が出たとき**
このエラーは、FirestoreのRulesで書き込みが拒否されているときに出ます。
学習中だけ、Firestore Rulesを次のようにして動作確認できます。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
これは開発用です。
本番公開では使わないでください。
本番では、ログインユーザーだけが必要なデータを読み書きできるようにします。
email-already-in-use** が出たとき**
これは、そのメールアドレスがすでに使われているという意味です。
学習中は、別のメールアドレスで試してください。
例:
test3@example.com
test4@example.com
test5@example.com
または、Firebase ConsoleのAuthenticationからテストユーザーを削除して、もう一度試します。
FirebaseFirestore isn't defined** が出たとき**
main.dart の上に、次の1行があるか確認します。
import 'package:cloud_firestore/cloud_firestore.dart';
なければ追加してください。
保存して、もう一度実行します。
flutter run
最短作業まとめ
読むのが大変な人は、ここだけ見てください。
1. importを確認
import 'package:cloud_firestore/cloud_firestore.dart';
2. register()内でユーザー作成後にこれを追加
await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'displayName': displayName,
'email': email,
'department': department,
'photoUrl': '',
'defaultRole': 'member',
'createdAt': FieldValue.serverTimestamp(),
'updatedAt': FieldValue.serverTimestamp(),
});
3. 保存して実行
flutter run
4. Firebase Consoleで確認
Authentication
↓
Users
Firestore Database
↓
users
チェックリスト
□ Firestore Databaseを有効にした
□ main.dartを開いた
□ cloud_firestoreをimportした
□ register()を差し替えた
□ createUserWithEmailAndPasswordのあとにset()を書いた
□ users/{uid} に保存する形にした
□ displayNameを保存した
□ emailを保存した
□ departmentを保存した
□ createdAtを保存した
□ updatedAtを保存した
□ 保存した
□ flutter runで実行した
□ Authenticationでユーザーを確認した
□ Firestoreのusersでプロフィールを確認した
ミニ確認問題
Q1. users/{uid} には何を保存しますか?
回答
ユーザーのプロフィールを保存します。
今回保存するのは、displayName、email、department、photoUrl、defaultRole、createdAt、updatedAt です。
Q2. なぜドキュメントIDに uid を使いますか?
回答
Firebase AuthenticationのユーザーとFirestoreのプロフィールを結びつけやすくするためです。
uid はユーザーごとに一意なので、プロフィールの保存先として使いやすいです。
Q3. FieldValue.serverTimestamp() は何をしますか?
回答
Firestore側の現在時刻を保存します。
作成日時や更新日時を保存するときに使います。
Q4. このページでnpmや環境変数は必要ですか?
回答
必要ありません。
このページでは、Firestoreにプロフィールを保存するコードを追加するだけです。
このページのまとめ
- Firebase Authenticationはログイン用アカウントを管理する。
- Firestoreはアプリ内で使うプロフィールを保存する。
- 新規登録後に、
users/{uid}にプロフィールを保存する。 uidはFirebase Authenticationがユーザーごとに発行するID。collection('users').doc(user.uid).set(...)でプロフィールを保存する。displayName、email、departmentを保存する。createdAtとupdatedAtにはFieldValue.serverTimestamp()を使う。permission-deniedが出たらFirestore Rulesを確認する。- このページではnpmや環境変数は不要。
次のページでやること
次のページでは、ログアウト処理を作ります。
FirebaseAuth.instance.signOut() を使って、ログイン状態を解除し、ログイン画面へ戻る流れを確認します。
