リファクタリング: 作成日時と更新日付の追加 (STEP 3 : 他のユーザのタスクが見れるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)
★前回の記事
Firebase Realtime Databaseでは、データの作成日時・更新日時は自動で付与されないので、クライアント側(javascript)で付与します。これに伴い、Cloud FunctionsもDatabaseの更新日時を使用するように変更します。データの作成日時・更新日時は、サンプルのアプリでは特に必要がないですが、アプリをリリースした後、問い合わせがあった場合の調査などに重要になります。
actionの更新
タスク作成時に、作成時間_createdAt
と_updatedAt
を付与し、更新時に_updatedAt
を更新します。
時刻関連の処理には、使いやすさのため、momentモジュールを使用します。
src/actions/todoActions.js
import moment from 'moment' // 追加 // 中略 export const addTodo = (uid, text) => { return (dispatch, getState, {getFirebase}) => { // 中略 const createdAt = moment().valueOf(); // 追加 firebase.push(`todos/${uid}`,{ completed: false, text, _createdAt : createdAt, // 追加 _updatedAt : createdAt // 追加 }) // 中略 } } export const toggleTodo = (uid, id) => { return (dispatch, getState, {getFirebase}) => { // 中略 const updatedAt = moment().valueOf(); // 追加 firebase.update(`todos/${uid}/${id}`, { completed: ! todo.completed, _updatedAt : updatedAt // 追加 }) // 中略 } }
database.rules.jsonの更新
_createdAt
と_updatedAt
を登録できるようにデータベースルールファイルを変更します。
database.rules.json
{ "rules": { "todos": { "$uid": { ".read": true, ".write": "$uid === auth.uid", "$todoId": { ".validate": "newData.hasChildren(['text', 'completed', '_createdAt', '_updatedAt'])", // 変更 "text": { ".validate": "newData.isString()" }, "completed": { ".validate": "newData.isBoolean()" }, "_createdAt": { // 追加 ".validate": "newData.isNumber()" }, "_updatedAt": { // 追加 ".validate": "newData.isNumber()" }, "$other": { ".validate": false } } } }, // 中略 } }
変更を反映します。
firebase deploy --only database
".validate": "newData.hasChildren(['text', 'completed', '_createdAt', '_updatedAt’])”
があるせいで、既存のタスクが更新できなくなってしまいました。今回は既存のタスクは削除します。次回からは初めから_createdAt
と_updatedAt
は付与しましょう。
Cloud Functionsの修正
タスクの作成トリガを/todos/{uid}/{todoId}/_createdAt
の作成、更新トリガを/todos/{uid}/{todoId}/_updatedAt
の更新とするように変更します。
また、recentUpdatedTodos
の_updatedAt
は、todos
の_updatedAt
から取得するように変更します。
fuctions/index.js
const addRecentUpdate = (uid, todoId, todo, eventType) => { // #1 return admin.database().ref('/users/' + uid + '/displayName').once('value').then((snapshot) => { const displayName = snapshot.val(); return (admin.database().ref('/recentUpdatedTodos/' + todoId).set({ uid, displayName, text: todo.text, // #2 eventType, _updatedAt: todo._updatedAt // #3 })); }); } exports.addRecentUpdateOnCreate = functions.database.ref('/todos/{uid}/{todoId}/_createdAt') // #4 .onCreate((snapshot, context) => { const uid = context.params.uid; const todoId = context.params.todoId; return snapshot.ref.parent.once('value').then((snapshot) => { // #5 const todo = snapshot.val(); return addRecentUpdate(uid, todoId, todo, 'CREATE'); }); }) exports.addRecentUpdateOnUpdate = functions.database.ref('/todos/{uid}/{todoId}/_updatedAt') // #6 .onUpdate((change, context) => { const todoId = context.params.todoId; const uid = context.params.uid; return change.after.ref.parent.once('value').then((snapshot) => { // #7 const todo = snapshot.val(); return addRecentUpdate(uid, todoId, todo, 'UPDATE'); }); })
- addRecentUpdateの引数のうち、
text
をtodo
に変更します(#1)。 text
をtodo.text
で取得します(#2)。recentUpdatedTodos
の_updatedAt
を、todo
の_updatedAt
から取得します(#3)。- データパスを、
/todos/{uid}/{todoId}/text
から/todos/{uid}/{todoId}/_createdAt
に変更します(#4)。 - 親ノードを取得する処理を追加します(#5)。
- 関数名を、
addRecentUpdateOnUpdateCompleted
からaddRecentUpdateOnUpdate
に変更し、データパスを、/todos/{uid}/{todoId}/completed
から/todos/{uid}/{todoId}/_updatedAt
に変更します(#6)。 - textノードを取得する処理から、親ノードを取得する処理に変更します(#7)。
デプロイします。
$ firebase deploy --only functions === Deploying to 'todo-sample-xxxxx’… i deploying functions Running command: npm --prefix "$RESOURCE_DIR" run lint > functions@ lint /Users/yuka/react/todo-sample/functions > eslint . ✔ functions: Finished running predeploy script. i functions: ensuring necessary APIs are enabled... ✔ functions: all necessary APIs are enabled i functions: preparing functions directory for uploading... i functions: packaged functions (56.34 KB) for uploading ✔ functions: functions folder uploaded successfully i functions: creating Node.js 6 function addRecentUpdateOnUpdate(us-central1)... i functions: updating Node.js 6 function addRecentUpdateOnCreate(us-central1)... i functions: updating Node.js 6 function limitRecentUpdatedTodos(us-central1)...
今回、functionの名前を変更したので、途中でaddRecentUpdateOnUpdateCompletedを削除するか聞かれます。”y”を選択します。
The following functions are found in your project but do not exist in your local source code: addRecentUpdateOnUpdateCompleted(us-central1) If you are renaming a function or changing its region, it is recommended that you create the new function first before deleting the old one to prevent event loss. For more info, visit https://firebase.google.com/docs/functions/manage-functions#modify ? Would you like to proceed with deletion? Selecting no will continue the rest o f the deployments. Yes i functions: deleting function addRecentUpdateOnUpdateCompleted(us-central1)... ✔ functions[addRecentUpdateOnUpdateCompleted(us-central1)]: Successful delete operation. ✔ functions[addRecentUpdateOnCreate(us-central1)]: Successful update operation. ✔ functions[limitRecentUpdatedTodos(us-central1)]: Successful update operation. ✔ functions[addRecentUpdateOnUpdate(us-central1)]: Successful create operation. ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/todo-sample-xxxxx/overview
functionのデプロイが完了しました。
動作確認
動作確認をします。
タスクを新規登録します。
データベースを確認します。
_createdAt
と_updatedAt
が追加されています。
recentUpdatedTodos
の_updatedAt
はtodos
のものと同じ時刻です。
タスクを更新します。
データベースを確認します。
_updatedAt
が更新されました。recentUpdatedTodos
の_updatedAt
もtodos
の時刻で更新されています。
以上で作成日時と更新日付の追加の処理の完了です。Firebase Realtime Databaseを使用する際は、最初から全てのデータに作成日時と更新日時を付与することを強くおすすめします。
★次回の記事
★目次