How to rollback uncommited relationship after using pushObject? - ember.js

Given a tag and post ManyToMany relationship defined as follow:
post.js
import Ember from 'ember';
import Model from 'ember-data/model';
import { hasMany } from 'ember-data/relationships';
export default Model.extend({
tags: hasMany('tag')
}
tag.js
import Ember from 'ember';
import Model from 'ember-data/model';
import { hasMany } from 'ember-data/relationships';
export default Model.extend({
posts: hasMany('post')
}
When adding tags to post using pushObject
let aPost = this.store.findRecord('post', 1),
aTag = this.store.findRecord('tag', 1);
aPost.get('tags').pushObject(aTag); // aPost is not commited yet
How to restore aPost.tags to its initial state?

Related

How setup an adapter to return data from an API for my application route in Ember data?

I'm learning to use ember data. I want to build an image searching app using Pixabay's free API.
I want to send search queries to adapter and get the results in route via model. First of all, I'm not sure how to create adapter for application route. I found many tutorials on ember data, they all built adapters and model for a specific model not on the application route.
app/routes/application.js
import Route from '#ember/routing/route';
export default Route.extend({
model(){
return this.store.findAll('application');
}
});
app/models/application.js
import DS from 'ember-data';
import Model from 'ember-data/model'
const { attr } = DS;
export default Model.extend({
largeImageURL : attr('string')
});
app/adapters/application.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host:"https://pixabay.com/api/?key=<API-KEY>&q=<queries>",
pathForType(){
return '/';
}
});

You need to pass a model name to the store's modelFor method

I have problem with making hasMany <=> belongTo relationship to work.
I have articles/show view, when I try to list article's comments but I keep recieving the error pointed in the title.
It's something with belongsTo: DS.belongsTo('article') but I couldn't figure out what it is.
Here are my files.
routes/articles/show.js
import Ember from 'ember';
import RSVP from 'rsvp';
export default Ember.Route.extend({
model(params) {
return RSVP.hash({
article: this.store.find("article", params.id),
comments: this.store.query('comment', { articleId: params.id })
});
}
});
controllers/articles/show.js
import Ember from 'ember';
const { computed: { alias, readOnly } } = Ember;
export default Ember.Controller.extend({
article: alias('model.article'),
comments: alias('model.comments'),
length: readOnly('comments.length')
});
templates/articles/show.hbs
<h3>Comments ({{comments.length}})</h3>
{{#each comments as |comment|}}
<p>Author: {{comment.user.name}}</p>
<p>Somebody said: {{comment.body}}</p>
{{/each}}
adapters/comment.js
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({});
serializers/comment.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
attrs: {
user: { embedded: 'always' },
article: { embedded: 'always' }
}
});
serializers/article.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
comments: { embedded: 'always' }
}
});
models/article.js
import DS from 'ember-data';
import Ember from 'ember';
const { attr, hasMany } = DS;
const { computed: { gt } } = Ember;
export default DS.Model.extend({
title: attr('string'),
content: attr('string'),
authorName: attr('string'),
authorAvatar: attr('string'),
authorUrl: attr('string'),
comments: hasMany('comment', {async: true}),
hasAvatar: gt('authorAvatar.length', 0)
});
Edit:
I added here the code for comment model as asked in the comments.
models/comment.js
import DS from 'ember-data';
const { belongsTo, attr } = DS;
export default DS.Model.extend({
article: belongsTo(),
user: belongsTo(),
body: attr('string')
});
And here is stacktrace from inspector:
ember.debug.js:16905 Assertion Failed: You need to pass a model name to the store's modelFor method
Error
at assert (http://ffl.com:8000/assets/vendor.js:16268:13)
at Object.assert (http://ffl.com:8000/assets/vendor.js:27196:34)
at assert (http://ffl.com:8000/assets/vendor.js:135212:37)
at Class.modelFor (http://ffl.com:8000/assets/vendor.js:145201:41)
at Class._internalModelForId (http://ffl.com:8000/assets/vendor.js:144337:29)
at Class._pushResourceIdentifier (http://ffl.com:8000/assets/vendor.js:145716:19)
at BelongsToRelationship.updateData (http://ffl.com:8000/assets/vendor.js:142394:36)
at BelongsToRelationship.push (http://ffl.com:8000/assets/vendor.js:142976:14)
at http://ffl.com:8000/assets/vendor.js:145795:20
at http://ffl.com:8000/assets/vendor.js:141943:18
defaultDispatch # ember.debug.js:16905
dispatchError # ember.debug.js:16888
onerrorDefault # ember.debug.js:30389
trigger # ember.debug.js:57833
(anonymous) # ember.debug.js:58717
invoke # ember.debug.js:339
flush # ember.debug.js:407
flush # ember.debug.js:531
end # ember.debug.js:601
run # ember.debug.js:724
join # ember.debug.js:746
run.join # ember.debug.js:21556
hash.success # rest.js:954
fire # jquery.js:3305
fireWith # jquery.js:3435
done # jquery.js:9242
(anonymous) # jquery.js:9484
I checked your issue and repo. The problem was just with comment serializer in Ember.js. It should be:
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
article: { embedded: 'always' },
user: { embedded: 'always' }
}
});
I cloned your project branch refactor-and-upgrade-ember but mirage is not done. So I looked at the code
headTags() {
let article = this.modelFor(this.routeName);
}
This is in routes articles show ,can you try and remove it and try.

Unit testing using ember-qunit controller action which access the store and methods

I have built a small Ember App. It has a controller which has an action named changeStatus(id). This method access the store and try to change an attribute value. I am relatively new to Ember. I don't know whether best way is to test it with Integration test or unit test? And how to test with either way.
Here is the sample code
Controller: user.js
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
changeStatus(id) {
const oUser = this.store.peekRecord('user', id),
let bCurrentValue = oUser.get('active');
if (bCurrentValue) {
oUser.set('active', false);
} else {
oUser.set('active', true);
}
//oUser.save();
},
}
});
Model: user.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default PatientIndexController;
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default Model.extend({
active: attr('boolean'),
});
Unit Test: user-test.js
import {moduleFor, test} from 'ember-qunit';
import Ember from 'ember';
moduleFor('controller:user', 'Unit | Controller | user', { });
test('Toggle user active status', function (assert) {
const contollerUser = this.subject();
contollerUser.send('changeStatus', 1);
assert.equal(contollerUser.store.peekRecord('user', 1).get('active'), 'true or false');
});
but I am not getting how to set some data to store. As when I call the function changeStatus() then it don't know about user model.
How to set a proper test. Thanks in advance.

Trying to get data with ember and django rest framework

I have installed Ember Django Adapter(EDA) and I have followed the tutorial and in the template everything is ok but I'm not getting data from my api... but when my model its connect to the api I get the following warning in the console.
WARNING: Encountered "articles" in payload, but no model was found for model name "article" (resolved model name using frontend#serializer:articles:.modelNameFromPayloadKey("articles"))
This is my code:
app/application/serializer.js
import DRFSerializer from '../serializers/drf';
export default DRFSerializer.extend({
});
app/application/adapter.js
import DRFAdapter from '../adapters/drf';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
export default DRFAdapter.extend(DataAdapterMixin , {
authorizer: 'authorizer:django'
});
app/router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('index');
});
export default Router;
app/models/articles.js
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default Model.extend({
title: attr('string'),
body: attr('string')
});
app/index/route.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.get('store').findAll('articles');
}
});
app/index/template.hbs
{{#each model as |article|}}
<article class="listing">
<h3>{{article.title}}</h3>
</article>
{{/each}}
You should use singular words when naming models, so change your model file to "article.js" and also change in route.js file to this.get('store').findAll('article');

ember.js: Make AdminRouteMixin from AuthenticatedRouteMixin?

Is there a more elegant way to prevent unauthorized access to an admin-only route than writing this in all of my admin routes?
export default Ember.Route.extend(AuthenticatedRouteMixin, {
beforeModel: function(){
if(!this.get('session.secure.admin')) this.transitionTo("dashboard");
}
});
Perhaps it's possible to extend AuthenticatedRouteMixin itself to make this kind of check?
Thanks!
Why not just make the mixin?
import Ember from 'ember';
import AuthenticatedRouteMixin from 'wherever/it/is'.
const { Mixin } = Ember;
export default Mixin.create(AuthenticatedRouteMixin, {
beforeModel(){
if(!this.get('session.secure.admin')) {
this.transitionTo("dashboard");
}
}
})
And then import it in your routes:
import Ember from 'ember';
import AdminCheckMixin from 'yourApp/mixins/routes/admin-check';
const { Route } = Ember;
export default Route.extend(AdminCheckMixin);