Where to place fixtures? - ember.js

Where should I define fixtures in an Ember JS app generated with ember-cli? I've tried numerous places, such as app.js and within a folder called "fixtures".

After digging around I discovered that changing Ember.MODEL_FACTORY_INJECTIONS = true; in the file app.js to Ember.MODEL_FACTORY_INJECTIONS = false; is solving the problem.
Through this question I also found another solution where you don't have to change the configuration:
Instead of defining the fixtures as described you have to use reopenClass:
//models/item.js
var Item = DS.Model.extend({...});
Item.reopenClass({
FIXTURES: [
{ id: 1, ... },
{ id: 2, ... }
]
});
export default Item
Happy developing with Ember and ember-cli :-)

Instead of using fixtures, the way I'm doing it in Ember CLI 0.0.40 is generating api stubs.
ember generate api-stub tasks
I'm a node.js beginner, but from the looks of it, it sets up an express server script to respond to the /tasks endpoint, corresponding to the name you pass to the command, in the format the Ember REST adapter is expecting. Then you simply fill in the empty array with your fixture data. Easy peesy!
The benefit I see is that I won't have to rework anything later to integrate with a restful api getting me one step closer to launching a real app some day.
This generator is not thoroughly documented yet. It's only displayed as an item in the ember help generate command, which I was brave/desperate/curious/stupid enough to try.

If you use findQuery to get your data you will get this error when using the method above:
Error while loading route: Error: Assertion Failed: Not implemented: You must override the DS.FixtureAdapter::queryFixtures method to support querying the fixture store.
To fix this I created an adapter for the model and implemented the queryFixtures method to return the fixtures.
#/adapters/[model-name].js
queryFixtures: function() {
return [ {
"key" : "value",
},
{
"key" : "value",
},
etc...
]
};
I had to do this in addition to reopenClass in my model definition as stated above. In fact it was the same data, I cut and pasted. This smells a little bad, but it works. I'm sure there's a better way to do this without duplicating the fixtures, I just don't know what it is.

I define it in the model folder
//models/item.js
var Item = DS.Model.extend({...})
Item.FIXTURES = [
{
id:1,
...
}
];
export default Item

Related

ember-data: having a hard time getting data into the store

I have an existing search app I built on the server-side that uses elasticsearch processed by python/flask. On the client side, it's using JS/jQuery and handlebars to parse and present the data.
I'd like to take it one step further and build it in ember, as the "controls" (filters, sorting, pagination, etc) make it a perfect candidate for an SPA.
I understand the ember fundamentals, but I feel like I've hit a wall with ember-data - i.e. how to get my data into the store so I can bind actions. Can somebody point me in the right direction?
My existing JSON API is accessed like this:
http://localhost:8000/search?q=shirt&paging=18&filter-price=100
and it returns JSON like this:
{
"aggregations": {
"breadcrumb": [],
"color": [],
"price": [],
"size_apparel": [],
"size_jewelry": []
},
"meta": {
"agg_list": [],
"default_sort": "",
"key_translations": {},
"paging": 18,
"paging_options": [],
"sort_methods": [],
"from": 0,
"hits": 89,
"pages": 5,
"q": "shirt"
},
"results": [
{
"creation_date": "",
"image": "",
"images": {
"altimg1": "",
"large": "",
"regular": "/",
"small": ""
},
"name": "This Product",
"price": "19.95",
"skuid": "ABC123",
"url": "shirt.html"
},
{...},
{...}
]
}
Is this usable or do I need to rewrite the back-end?? I've tinkered with accessing the data and have something very rough working. I can actually see the 'results' data, but I have NO IDEA how to access the 'meta' and 'aggregations' data. I think this is "multiple models in the sam payload" and RSVP.hash should work...but ember-data seems to have a requirement that each model have an id. That makes sense for the "results" model, but not for aggregations and definitely not for meta.
For now I just want to get it to show up.
For starters, my adapter is:
export default DS.RESTAdapter.extend({
host: 'http://localhost:8000',
pathForType() {
return 'search';
}
});
Test controller is:
export default Ember.Controller.extend({
queryParams: ['q','paging'],
q: 'shirt',
paging: '18'
});
my 'result' model is:
const { attr } = DS;
export default Model.extend({
'creation_date': attr('string'),
'has_pricerange': attr('string'),
'image': attr('string'),
'name': attr('string'),
'price': attr('string'),
'skuid': attr('string'),
'url': attr('string')
});
route:
export default Ember.Route.extend({
model(params) {
return this.store.query('result', {
q: params.q,
paging: params.paging
});
}
});
serializer:
export default DS.RESTSerializer.extend({
primaryKey: 'skuid'
});
This is so easy to do with jquery - you just $.get and then access the data with object notation. I know ember is not jquery, but it seems like it should be easier to access data. Am I missing something? Taking the wrong approach? Should I start from scratch?
Ember Data is a great piece of the Ember puzzle, but by no means required. Whether or not you should use Ember Data really depends on the nature of your data, the control of your API, and your desired futureproofability
Nature of your Data
Ember Data really excels at your typical model/entity type data. "Things" that have attributes, and can relate to each other. If your data follows that pattern then Ember Data could be a great fit.
Control of your API
As mentioned in the other answer, you get a lot for free if you can buy into a JSON API format. This has become the standard for Ember Data, but is not exclusive to Ember. A lot of server-side options will have ways to serialize these resources easily with many existing frameworks. If you can't change the data coming from the server, or if it's easier to just handle it on the front-end, you can go down the path of customizing the adapters/serializers in Ember.
Desired Futureproofability
Ember Data allows you to swap out the adapter/serializer while keeping your models in tact. This is desirable if you want your application to handle different sources in the future, maybe swap from using your own API to using a local storage, or a 3rd-party service like firebase. If don't plan on much changing, you can do your basic ajax calls and return a promise within your model hook and Ember will work more or less the same. I would recommend using ember-network which is spec'ed against the fetch API and will likely become more and more supported as a FastBoot compatible request.
Other things to consider is that Ember Data and using the Ember Object can be heavy depending on the amount of instances of each model you'll be passing in.
Others are tackling this problem, too. Toran Billups has pulled the redux pattern with ember-redux, which is another great way of thinking about how you approach your data.
Your use case
So you could:
Use Ember Data with find
Taking a look at the shape of your data, it looks like you're providing more of a search service than querying for specific models/entities. Ember Data does have a find method, but the amount of metadata you're providing it might be overloaded for the model use case.
Forget Ember Data and use search end point
model: function(params), Use the params from the model hook to construct the url to the search end point, and return a promise (add then as needed to shape the data)
Query the search end point (API refactor)
Similar idea as above, but you would use get the product id's and use those to query the ember data store for the products.
Something similar to:
fetch("service-end-point?with=queryparams")
.then(result => {
return {
products: this.store.findMany(Product, result.ids);
};
});
I think it'd be easiest to get started just handling and shaping the data directly in the controller, and skipping Ember Data. If you want specific computed property bindings there's no reason why you can extend Ember.Object with the shape you want and then use something like .map to take the result from the network request and apply it like payload => Object.create(payload).
Let me know if you have any questions surrounding any of these ideas.
I recommend you read this section of the guide, specifically the bit about $.getJSON. Ember is designed to use a powerful store. It's much easier to use if you're using a standard api (e.g. JSON API); you can just use Ember data code directly. But if not, you will have to write some serializer code so Ember knows how to use your api. Once that's done though, your component code won't be coupled to your data fetching code.
You can use $.getJSON if you are still prototyping, though.

Ember.js: How to integration test components that interact with ember-data models

I'm building a relatively straight-foward comment-list component. I want to pass in the commentable model (say a Post) and have the component take care of creating, editing, deleting comments. Right now I pass around all the various actions and it's been extremely brittle.
How do I create a true instance of an Ember Data model in a component integration test?
My immediate thought was to import the model then .create({}) it but that errors with use this.store.createRecord() instead
/* jshint expr:true */
import { assert } from 'chai';
import { describeComponent, it } from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import Post from 'ownersup-client/post/model';
describeComponent( 'comment-list', 'Integration: CommentListComponent', {
integration: true
},
function() {
it('renders all of the comments', function() {
const model = Post.create({ title: 'title' });
model.get('comments').createRecord({ body: 'One Comment' })
this.render(hbs`{{comment-list model=model}}`);
assert.lengthOf(this.$('.comment-list-item'), 1);
});
}
);
Anyone have any thoughts?
Among all Ember test helpers, the store is only available from moduleForModel.
Here's how this test helper does it (source):
var container = this.container;
var store = container.lookup('service:store') || container.lookup('store:main');
You can do the same inside your test. You can also put it into a helper so that you don't have to copy-paste a lot.
Note that it will only work for an integration test. You can turn any test into integration one by starting the app using the startApp test helper that is bundled with your Ember CLI boilerplate.
The new ember mocha release 0.8.4 contains a new, public way to inject services such as the store. There's a guides section coming soon with an example (see https://github.com/emberjs/guides/blob/master/source/testing/testing-components.md)
essentially, in your beforeEach you want add the following line: this.inject.service('store');, making the store accessible as this.get('store') in your tests.
Here's a link to the pull request for the new change: https://github.com/switchfly/ember-test-helpers/pull/105
General answer for people who are struggled with similar things related to injecting in integration tests.
Everything depends on which version and solutions you have in your project.
When you have an integration test with module
(import { module } from 'ember-qunit';)
you can use this.owner.lookup('service:store') inside your test
for more information, there is a great article from Dockyard
https://dockyard.com/blog/2018/01/11/modern-ember-testing

How to use emberfire to query a firebase db for all items with name equalTo xyz in ember.js 2.0.0?

I'm new to ember.js and firebase.
I've been trying to make something that needs me to query the DB for a key matching a defined value.
According to guides.emberjs.com, the following example should work:
this.store.query('person', { filter: { name: 'Peter' } }).then(function(peters) {
// Do something with `peters`
});
But it doesn't. Apparently because I'm using the emberfire addon.
After literally hours of googling, there was no clear solution.
The emberfire docs talk about the available arguments.
Arguments
orderBy - String - The property ...
.
.
.
equalTo - String, Number, Null - Creates a query which includes children which match the specified value.
And present an example...
// app/routes/dinosaurs.js
export default Ember.Route.extend({
model: function() {
return this.store.find('dinosaur', {
orderBy: 'height',
limitToLast: 10,
startAt: 5
});
}
});
Although without showing how to use 'equalTo'.
I've tested all of them, but I failed to understand how equalTo works.
There are other solutions on SO about this, but they are all pre-v2.0.0. So I don't think they would work post v2.0.0.
Ember.js debug info:
DEBUG: -------------------------------
DEBUG: Ember : 2.0.0
DEBUG: Ember Data : 2.0.0
DEBUG: Firebase : 2.3.1
DEBUG: EmberFire : 1.6.0
DEBUG: jQuery : 1.11.3
DEBUG: -------------------------------
The database in use: https://shoutoutdb.firebaseio.com/users
I don't fully understand how equalTo should work here, but I'm not getting any clue either. Hopefully someone here will be willing to help.
If you think the question needs any kind of improvement, kindly ask. I've detailed it as well as I thought I should.
Thanks in advance. :)
EDIT:
Code I tried to use:
$E.store.find('user',{name:'Alpha'}).then(
function (data) {
//stuff done with the data
}
);
I also tried multiple different versions around this code. Nothing worked, so I don't think it's even worth mentioning them here.
Using the querying capabilities you can combine orderByChild and equalTo to get the desired result:
ref.child('people').orderByChild('name').equalTo('Peter').on('value', ...);
There is an example in the web API reference for equalTo and in the Web guide on complex queries.
So, in EmberFire, this would translate to the following:
this.store.query('person', { orderBy: 'name', equalTo: 'Peter' });
Although tstirrat's response will get you by in most cases, There is an Ember addon for querying a firebase search.
You can check it out here:
https://www.npmjs.com/package/ember-emberfire-find-query

ember/ember-cli - impossible url fetched while routing

I am new to Ember, but I got a successful "app" with it, then i'm trying to "port" it to ember-cli.
I have a quite empty main page, and a link to the about page: main and about routes are defined.
However I got a 404 "/mains" not found when accessing /… why the hell is he adding an extra "s"?
I've uploaded the project:
https://github.com/Leryan/testember/
https://raw.githubusercontent.com/Leryan/testember/master/2015-03-21-202815_1920x1080_scrot.png
You'll see a picture with the problem: when accessing the website root, ember try to fetch "/mains" …
Thanks
Ember is looking for the all the records of the type 'main' by calling this url.
This is because in the router "main.js" you are using this.store.find method, which pluralizes the model type to retrieve all the records for this model ("/mains"):
var MainRoute = Ember.Route.extend({
model: function() {
return this.store.find('main');
}
});
But it looks like you want to use fixtures instead?
Therefore you have to use the FixtureAdapter for the desired route and define the fixtures for the model. To use the FixtureAdapter you must rename your existing adapter "all.js" to "application.js" or "main.js" depending where you want to use it.
And furthermore you have to use reopenClass to assign any fixtures in your model "main.js":
Main.reopenClass({
FIXTURES : [
{ id: 1, name: "blah" },
{ id: 2, name: "blah2" }
]
});
Here is the ember gudie for the fixture adapter:
http://emberjs.com/guides/models/the-fixture-adapter/

Adding New Ember.js Objects/Records when DB Provides ID

I'm experimenting with Ember.js, Node.js and MongoDB. I've based my noodling on the excellent video on the Ember site and Creating a REST API using Node.js, Express, and MongoDB. I've hit a roadblock on the Ember.js side trying to get my create record functionality working.
Currently, when a user creates a record in my sample application, two will show up in the listing. This is happening because when I save my record to the server, a new ID is created for that record by MongoDB. When the response is returned (containing the object with the new ID), the record is duplicated until I refresh the page. One has the new Mongo-supplied ID and the other has a NULL.
Here is where I create the new object:
App.NewwineRoute = Ember.Route.extend({
model: function() {
return App.Wine.createRecord();
}
});
Here is where I store the record to MongoDB:
App.NewwineController = Ember.ObjectController.extend({
doneEditing: function() {
this.get('store').commit();
this.transitionToRoute('wines');
}
});
I'm curious what the best way to handle this is when using ember-data? I've tried all kinds of tricks and worn my connection out searching for examples.
The closest I've been is a nasty hack of setting an id of -1 to the new object/record and then attempting to remove it after the commit. Sadly, the object/record wouldn't really be removed, just show up blank in my list. Plus, I couldn't create any objects/records with an id of -1 from that point on (because one already exists). Seems like a dead-end.
Thanks in advance.
>'.'<
SOLUTION:
I was able to glean the solution to the problem from the following AMAZING examples:
Ember.js CRUD REST
Node.js REST Server for Ember
For others that have had the ID problem, the App.Adapter in the above example handles the mapping from "_id" to "id".
App.Adapter = DS.RESTAdapter.extend({
serializer: DS.RESTSerializer.extend({
primaryKey: function (type){
return '_id';
}
})
});
Inside of the example's Node.js service, the DB calls map "id" to "_id":
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
Thanks again to ddewaele for sending over the example, it was a great tutorial for linking these technologies together.