I'm getting started with my first Ember/Firebase application and having trouble finding documentation that goes beyond public data.
My goal is to have an application where signed in users can create and view their own data. I see that Firebase suggests this rule for such a situation:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
But I can't find out any information about how this would work on the Ember end. For example, assuming I have an "entry" model that I am saving:
save(model) {
model.save().then( () => {
this.transitionToRoute('index');
}, error => {
console.error(`error: ${error}`);
})
},
Not sure if I need to be storing a uid in the model?
And then if I want the user to get a listing of their own entries:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('entry');
}
});
This produces the following error:
ember.debug.js:30610 Error while processing route: index permission_denied at /entries: Client doesn't have permission to access the desired data. Error: permission_denied at /entries: Client doesn't have permission to access the desired data.
At this point I'm not sure what I should be doing –– do I need to build a custom URL or add a namespace in my firebase adapter to add a users/xxx prefix? Or etc?
Cannot find any documentation/tutorials/walkthroughs that cover anything beyond public read/write data.
I made this work eventually. It basically boiled down to storing the uid from Firebase auth in a service after login (I added ember-local-storage in case of page refresh), and then adding a pathForType method to the application adapter to nest all users data under users/${uid}, so in firebase data is ending up in this configuration: users/${uid}/entries/${entry_id}.
import FirebaseAdapter from 'emberfire/adapters/firebase';
import Ember from 'ember';
export default FirebaseAdapter.extend({
/* inject service to access uid */
journalist: Ember.inject.service('journalist'),
/* path for type nests /entries under users/${uid} */
pathForType(type) {
let uid = this.get('journalist.uid');
let path = Ember.String.pluralize(type);
return `users/${uid}/${path}`;
}
});
import Ember from 'ember';
export default Ember.Route.extend({
/* injecting service to set uid */
journalist: Ember.inject.service('journalist'),
beforeModel() {
return this.get('session').fetch().catch();
},
actions: {
signIn(provider) {
this.get('session').open('firebase', {provider: provider}).then(data => {
/* setting uid in service for later retrieval elsewhere */
this.get('journalist').setUID(data.uid);
this.transitionTo('entries');
});
},
signOut() {
this.get('session').close().then(() => this.transitionTo('application'));
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
/* nothing special required for ember data save, findAll, etc, adapter takes care of everything */
model() {
return this.store.findAll('entry');
}
});
import Ember from 'ember';
import { storageFor } from 'ember-local-storage';
export default Ember.Service.extend({
uid: null,
localStore: storageFor('journalist-session'),
init() {
const localStore = this.get('localStore');
this.set('uid', localStore.get('uid'));
},
setUID(id) {
this.set('uid', id);
this.set('localStore.uid', id);
}
});
import StorageObject from 'ember-local-storage/local/object';
const Storage = StorageObject.extend();
Storage.reopenClass({
initialState() {
return {
uid: null
};
}
});
export default Storage;
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}