I have my mirage setup with two models and factories like so
mirage/models/user.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
posts: hasMany()
});
mirage/models/post.js
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
user: belongsTo()
});
mirage/factory/user.js
import { Factory, faker } from 'ember-cli-mirage';
export default Factory.extend({
name(i) {
return `Person ${i}`;
},
afterCreate(user, server){
server.create('post', 10, { user });
}
});
mirage/factories/post.js
import { Factory, association } from 'ember-cli-mirage';
export default Factory.extend({
title(i) {
return `Show ${i}`;
},
description(){
return faker.lorem.paragraph();
},
user: association()
});
mirage/serializers/user.js
import { RestSerializer } from 'ember-cli-mirage';
export default RestSerializer.extend({
include: ['posts']
});
mirage/scenarios/default.js
export default function(server) {
server.createList('user', 10);
}
In my model hook I make a request to this.get('store').findAll('user') and then I loop over it in my template. The problem I have is that this get request only includes 1 post per user. What I would have expected is to get 10 posts created per user.
What am I missing here?
Related
I have been trying to implement pagination (I've tried both ember-cli-pagination and ember-simple-pagination) for my application but I've had a lot of issues. So I decided to try custom pagination and noticed that I cannot pass parameters into my query. For instance, when visiting my api at: http://jsonplaceholder.typicode.com/posts?_start=0&_limit=10, start and limit both work properly. When calling it in my route, it seems to ignore that entirely and just give me all entries. I would appreciate all insight into what I am doing wrong or how to properly implement pagination in this case.
app/adapters/post.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host:'https://jsonplaceholder.typicode.com',
pathForType(){
return 'posts';
}
});
app/models/post.js
import DS from 'ember-data';
const { Model } = DS;
export default Model.extend({
user:DS.belongsTo('user'),
title:DS.attr('string'),
body:DS.attr('string'),
});
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
You need define the query params in both side Route and Controller.
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
queryParams = {
start: {
refreshModel: true
},
limit: {
refreshModel: true
}
},
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
And inside app/controllers/post.js
import Controller from '#ember/controller';
export default class ArticlesController extends Controller {
queryParams = ['start', 'limit'];
start = 1;
limit = 5;
}
Ember by default does not call model when query params are changed. We tell it to do so any time start/limit changes, through refreshModel: true.
I am having issue using ember-cli-mirage. My instance of mirage is configured to use the RESTSerializer and the EmbeddedRecordsMixin for relationships. I am able to get records with relationship without a problem, however when I save the parent record I get the following error coming from the ember-data code:
RangeError: Maximum call stack size exceeded
Weirdly enough, if I just removed the EmbeddedRecordsMixin everything works fine. Is there some restriction or special thing you need to do use the EmbeddedRecordsMixin with mirage
// models/artist.js
import DS from 'ember-data';
const { attr, hasMany, Model } = DS;
export default Model.extend({
name: attr('string'),
genre: attr('string'),
country: attr('string'),
bio: attr(),
albums: hasMany('album', {
async: false
}),
songs: hasMany('song', {
async: false
})
});
// serializers/artist.js
import DS from 'ember-data';
const { RESTSerializer } = DS;
export default RESTSerializer.extend(EmbeddedRecordsMixin, {
attrs: {
albums: {
embedded: 'always'
},
songs: {
embedded: 'always'
}
}
});
// mirage/models/artist.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
albums: hasMany(),
songs: hasMany()
});
// mirage/factories/artist.js
import { Factory, faker } from 'ember-cli-mirage';
export default Factory.extend({
name() {
return faker.name.findName();
},
genre() {
return faker.hacker.noun();
},
country() {
return faker.address.country();
},
bio() {
return faker.lorem.sentence();
},
afterCreate(artist, server) {
server.createList('album', 3, { artist });
server.createList('song', 3, { artist });
}
});
// mirage/serializers/artist.js
import { RestSerializer } from 'ember-cli-mirage';;
export default RestSerializer.extend({
embed: true,
include: ['songs', 'albums']
});
In my response from server i have id attribute like 'id'. But to update record i need to send in request id like '_id'. I try to use serializeId serializeId method. My adapter looks like
import DS from 'ember-data'
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-
mixin'
import Ember from 'ember'
import Inflector from 'ember-inflector'
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:token',
pathForType (modelName) {
let underscored = Ember.String.underscore(modelName)
return Inflector.inflector.pluralize(underscored)
}
})
and voicemail serializer
import ApplicationSerializer from './application'
import DS from 'ember-data'
import Ember from 'ember'
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'id',
attrs: {
history: {embedded: 'always'}
},
serializeIntoHash (data, type, snapshot, options) {
let root = Ember.String.decamelize(type.modelName)
data[root] = this.serialize(snapshot, options)
},
serializeId (snapshot, json, primaryKey) {
let id = snapshot.id
json['_id'] = id
}
})
But serializeId method did not called during serializing. And in my payload i still get id like 'id' instead '_id'. How to solve my issue?
UPDATED
I find in ember code that serializeId runs only if ds-serialize-id feature is enabled.
serialize(snapshot, options) {
let json = {};
if (options && options.includeId) {
if (isEnabled('ds-serialize-id')) {
this.serializeId(snapshot, json, get(this, 'primaryKey'));
} else {
const id = snapshot.id;
if (id) {
json[get(this, 'primaryKey')] = id;
}
}
}
To run serializeId method i turn on ds-serialize-id property in enviroment.js
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. 'with-controller': true
'ds-serialize-id': true
}
}
I think that isues solved.
I do 'server side validation'. In route in method 'catch' get errors from server. And I want pass this errors in template.
How to pass errors in template from route?
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Route.extend({
model() {
return this.store.createRecord('project');
},
actions: {
save(project) {
var router = this;
var errors = router.controllerFor('project.new').get('errors')
project.save().then(function(project){
router.transitionTo('projects.show', project);
}).catch(function(resp) {
// how to pass this errors in template ????
console.log(resp.errors);
});
}
},
});
From router.js
this.route('projects', function() {
this.route('new');
this.route('show', { path: '/:project_id' });
});
From Component
import Ember from 'ember';
import DS from 'ember-data'
export default Ember.Component.extend({
actions: {
save() {
this.project.set('colors', colors);
this.sendAction('save');
}
},
...
});
Closure Actions! (Assuming a recente version of - Ember 1.13+). Closure actions can have a return value, unlike regular actions.
On your template you do:
{{my-component mySave=(action 'save')}}
And in your component you do
import Ember from 'ember';
import DS from 'ember-data'
export default Ember.Component.extend({
actions: {
save() {
this.project.set('colors', colors);
let result = this.attrs.mySave();
//do something with result
}
},
...
});
And then in your controller:
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Controller.extend({
actions: {
save(project) {
var router = this;
var errors = router.controllerFor('project.new').get('errors')
project.save().then(function(project){
router.transitionTo('projects.show', project);
}).catch(function(resp) {
return resp.errors;
});
}
},
});
I would also recommend this article on Closure Actions which is very helpful.
EDIT: I initially replied with the action being on the route (as in your example) but #Kitler correctly reminded that closure actions communicate with the controller or another component. I don't know if that's an option for the OP?
I am trying to create and save a model in Ember but only the first entry in my form is saving leaving the others blank.
Before saving all of the models attributes are correct. (shown with logs)
Any help greatly appreciated!
My Model is:
import DS from 'ember-data';
export default DS.Model.extend({
endpoint: DS.attr('string'),
playerVersion: DS.attr('string'),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date')
});
My Route is:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('account');
}
});
My Controller is:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
save: function() {
var _this = this;
var model = this.get('model');
console.log(model.get('endpoint')); //Shows correct endpoint
console.log(model.get('playerVersion')); //Shows correct playerVersion
model.save().then(function(account) {
console.log(model.get('endpoint')); //Shows correct endpoint
console.log(model.get('playerVersion')); //Shows nothing
_this.transitionToRoute('accounts.index');
});
return false;
}
}
});
UPDATE - Was some settings needed on the custom Serializer needed.
export default JsonApiSerializer.extend({
keyForAttribute: function(key) {
//return Ember.String.dasherize(key);
return Ember.String.camelize(key);
},
keyForRelationship: function(key) {
//return Ember.String.dasherize(key);
return Ember.String.camelize(key);
},
keyForSnapshot: function(snapshot) {
//return Ember.String.dasherize(snapshot.typeKey);
return Ember.String.camelize(snapshot.typeKey);
},
});