First a Merry Xmas to you and thanks for helping with suggestions.
My question is still on emberjs namespace but this time in the context of a suite of multiple emberjs apps which will be contained within multiple rails-engine, so that each emberjs app is a standalone app with its own controllers, models, views and routers. However, they will still need to share ember-data associations. These rails-engines will inturn be included in the main-rails app where each engine represents a major feature of the app.
In this jsfiddle, I came up with 3 approach to namespace, but I will like to know which one is the emberjs way:
**Approach 1**
//Each emberjs app with its own namespace
MainRailsApp = Ember.Application.create();
RailsEngine = Ember.Namespace.create();
RailsEngine2 = Ember.Namespace.create();
MainRailsApp.Store= DS.Store.extend(); **inherits from Ember.Application**
MainRailsApp.Router = Em.Router.extend() **inherits from Ember.Application**
console.log(RailsEngine.toString()); //RailsEngine
console.log(RailsEngine2.toString()); //RailsEngine2
RailsEngine.Model = DS.Model.extend
RailsEngine2.model = DS.Model.extend
Can this model's share association though they inherit from different namespace
Contact.Model = RailsEngine.Model.extend({
address: DS.attr('string'),
user: DS.belongsTo('User.Model')
});
User.Model = RailsEngine2.Model.extend({
name: DS.attr('string'),
contacts: DS.hasMany('Contact.Model'),
});
**Approach 2**
//All the different emberjs apps share one namespace but different instances
Yp = Ember.Namespace.extend();
UserRailsEngine = Yp.create();
ContactRailsEngine = Yp.create();
PaymentRailsEngine = Yp.create();
Yp.Jk = Ember.Application.extend();
Yp.Jk.create();
Yp.Router = Em.Router.extend(); **inherits from the Ember.Namespace**
Yp.Store = DS.Store.extend({ }); **inherits from the Ember.Namespace**
console.log(UserRailsEngine.toString()); //UserRailsEngine
console.log(PaymentRailsEngine.toString()); //PaymentRailsEngine
UserRailsEngine.Model = DS.Model.extend
ContactRailsEngine.Model = DS.Model.extend
Can this models share association, they have one namespace but different instance
Contact.Model = ContactRailsEngine.Model .extend({
address: DS.attr('string'),
user: DS.belongsTo('User.Model')
});
User.Model = UserRailsEngine.Modelextend({
name: DS.attr('string'),
contacts: DS.hasMany('Contact.Model')
});
**Approach 3**
//One namespace but multiple subclasses of the namespace for each emberjs app
Mynamespace = Ember.Namespace.extend();
Order = Mynamespace.extend();
OrderRailsEngine = Order.create();
Event = Mynamespace.extend();
EventRailsEngine = Event.create();
console.log(OrderRailsEngine.toString()); //OrderRailsEngine
console.log(EventRailsEngine.toString()); //EventRailsEngine
**Additional questions**
1. Can I still associate ember-data models using hasMany and belongsTo in all of the 3 approach.
I am still not sure how the router will be handled. What do you think the namespace should be in the main-app and each of the rails-engine, so that they still work seamlessly.
What your suggestion on how to handle ember-data DS.Store namespacing since each ember-data model will be namespaced to each engine and I still want the ember-data DS.Store to recognize and work with the the different emberjs models contained in the engines.
Are Ember.Namespace auto-initialized just like Ember.Application is auto-initialized.
Alternative patterns are welcome.
Many thanks for your time.
A modified approah 2 seems to be the emberjs way to go. All the different emberjs apps will still share one namespace but instead of different instances of that namespace, they will share one instance. Final jsfiddle
This approach can be seen from the code pasted below, which was extracted from the link below:
https://github.com/emberjs/data/blob/master/packages/ember-data/tests/integration/embedded/embedded_dirtying_test.js
var attr = DS.attr;
var Post, Comment, User, Vote, Blog;
var Adapter, App;
var adapter, store, post;
var forEach = Ember.EnumerableUtils.forEach;
App = Ember.Namespace.create({ name: "App" });
User = App.User = DS.Model.extend({
name: attr('string')
});
Vote = App.Vote = DS.Model.extend({
voter: attr('string')
});
Comment = App.Comment = DS.Model.extend({
title: attr('string'),
user: DS.belongsTo(User),
votes: DS.hasMany(Vote)
});
Blog = App.Blog = DS.Model.extend({
title: attr('string')
});
Post = App.Post = DS.Model.extend({
title: attr('string'),
comments: DS.hasMany(Comment),
blog: DS.belongsTo(Blog)
});
Adapter = DS.RESTAdapter.extend();
Adapter.map(Comment, {
user: { embedded: 'always' },
votes: { embedded: 'always' }
});
Adapter.map(Post, {
comments: { embedded: 'always' },
blog: { embedded: 'load' }
});
adapter = Adapter.create();
store = DS.Store.create({
adapter: adapter
});
So in the contest of using it across rails engines it becomes:
//App = Ember.Namespace.create();
App = Ember.Namespace.create({ name: "App" });
Main = App.MainApp = Ember.Application.extend();
Main.create();
UserEngine = App.UserEngine = DS.Model.extend({
name: DS.attr('string')
});
VoteEngine = App.VoteEngine = DS.Model.extend({
voter: DS.attr('string')
});
console.log(Main.toString()); //App.MainApp
console.log(UserEngine.toString()); //App.UserEngine
console.log(VoteEngine.toString()); //App.VoteEngine
Related
I'm trying to set up a hasMany relationship between two models and a hasOne (belongsTo in the current version of Ember Data) between the hasMany and hasOne.
I'm working with Ember Data and have a made a RESTful API that works according to Ember's conventions. All the classes can be queried individually.
Bookmark = hasMany -> Termbinding
Termbinding = belongsTo -> Term
Term = belongsTo -> Termbinding
So the goal is to fetch a Bookmark and get the Terms that are attached to it through the Termbinding. I would already be pretty happy to get the Bookmark to Termbinding relation working. I went through all questions posted on here, sadly enough that didn't work.
Router.js
var Router = Ember.Router.extend();
Router.map(function() {
this.resource('bookmarks', { path:'bookmarks'});
this.resource('bookmark', { path:'bookmarks/:bookmark_id' });
this.resource('termbindings', { path:'termbindings' });
this.resource('termbinding', { path:'termbindings/:termbinding_id' });
});
export default Router;
Bookmark.js
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding')
});
export default Bookmark;
Termbinding.js
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark')
});
export default Termbinding;
I hope someone can help me because this is preventing me from using Ember for my bookmark application. Thanks in advance.
It might be wise to explicitly specify your inverses, i.e.
var Termbinding = DS.Model.extend({
bookmarkId: DS.attr('number'),
termId: DS.attr('number'),
termOrder: DS.attr('number'),
bookmarks: DS.belongsTo('bookmark', { inverse: 'termbinding' })
});
export default Termbinding;
var Bookmark = DS.Model.extend({
url: DS.attr('string'),
description: DS.attr('string'),
visits: DS.attr('number'),
termbinding: DS.hasMany('termbinding', { inverse: 'bookmarks' })
});
export default Bookmark;
Ember Data will try to map inverses for you, however, it is not without faults. It could possibly be that your pluralization of 'bookmarks' on a DS.belongsTo relationship is throwing off its automatic inverse mapping. Typically for belongsTo you would use the singular, 'bookmark'. Conversely, your hasMany would be termbindings: DS.hasMany('termbinding')
Also, if you could show where you're invoking the models that would be greatly appreciated. Typically I find that creating a JSbin at emberjs.jsbin.com helps me isolate the problem and also provides a collaborative space to debug and experiment.
I have got this route retrieving 2 models:
App.PanelRoute = Ember.Route.extend({
model: function(){
var topologymin = this.store.find('topologymin');
var metricmap = this.store.find('metricmap', { param1: 'something'})
return Ember.RSVP.hash({
topologymin: topologymin,
metricmap: metricmap
});
});
This makes 2 calls:
http://localhost/topologymins
http://localhost/metricmaps?param1=something
If I go to another route and again to this one, it makes again the call with the params, not the other one:
http://localhost/metricmaps?param1=something
But, as its the same call to retrieve the same records I would like them to be cached like in the other call.
How does it know when to call the server and when its not necessary? Is it possible to do that?
My models:
App.Topologymin = DS.Model.extend({
siteGroup: DS.attr('string'),
sites: DS.hasMany('site')
});
App.Metricmap = DS.Model.extend({
profile: DS.attr('string'),
link: DS.attr('string'),
services: DS.attr()
});
When you fire a request based on params Ember Data doesn't know how those params necessarily translate into the models (aka it doesn't know that you have all of the records that have some sort of relationship param1). You can cache it yourself, but then you'd still need some sort of way of knowing those records from other records in your store.
App.PanelRoute = Ember.Route.extend({
model: function(){
var met = this.get('fetchedBeforePromise'),
topologymin = this.store.find('topologymin'),
metricmap = met || this.store.find('metricmap', { param1: 'something'});
this.set('fetchedBeforePromise', metricmap);
return Ember.RSVP.hash({
topologymin: topologymin,
metricmap: metricmap
});
});
I would get the records of my field children. Here the code:
App.User = DS.Model.extend({
name: DS.attr('string'),
online: DS.attr('boolean')
});
App.List = DS.Model.extend({
name: DS.attr('string'),
children: DS.hasMany('App.User'),
online: function() {
var users = this.get("children");
return users.reduce(0, function(previousValue, user){ // no record founds
return previousValue + user.get("online");
});
}.property("children.#each.online")
});
But App.List.find(1).get('online') returns no record. (For some reason I cannot specify that App.List.children contains many records, of type App.Users, as embedded records).
Here is the fiddle: JSBIN and it's output
How I can solve my issue?
Define the embedded Model on your Adapter map:
App.List = DS.Model.extend({
name: DS.attr('string'),
users: DS.hasMany('App.User'), //use "users" as the property name to mantain ember's naming conventions
...
});
App.Adapter = DS.RESTAdapter.extend();
App.Adapter.map('App.List', {
users: {embedded: 'always'} //you can use `always` or `load` which is lazy loading.
});
App.Store = DS.Store.extend({
revision: 12,
adapter: App.Adapter.create()
});
Hope it helps
I'm working with Ember with Rails Backend
Ember.VERSION : 1.0.0-rc.3 ember.js:349
Handlebars.VERSION : 1.0.0-rc.3 ember.js:349
jQuery.VERSION : 1.9.1
I have three models
App.SocialNetwork = DS.Model.extend({
name: DS.attr('string'),
actors: DS.hasMany('App.Actor'),
relations: DS.hasMany('App.Relation'),
});
App.Actor = DS.Model.extend({
name: DS.attr('string'),
x: DS.attr('number'),
y: DS.attr('number'),
social_network: DS.belongsTo('App.SocialNetwork'),
relations: DS.hasMany('App.Relation'),
isSelected: function () {
return false;
}.property(),
});
App.Relation = DS.Model.extend({
name: DS.attr('string'),
actors: DS.hasMany('App.Actor'),
social_network: DS.belongsTo('App.SocialNetwork'),
});
And Inside my RelationsController I want to create a new instance of Relation
I tried to do it like this
App.RelationsController = Ember.ArrayController.extend({
currentRelation: null,
add: function () {
// get the selected actors
var actors = this.get('socialNetwork.actors').toArray().filter(function (element) {
return element.get("isSelected") == true;
});
// create the new relation with those actors
var newRelation = App.Relation.createRecord({
actors: actors,
name: "New Relation",
});
this.set('currentRelation', newRelation);
this.get('content').pushObject(newRelation);
this.get('store').commit();
},
});
But the relation is not being stored, and I debug the new record created and it doesn't have any actors or social network associations.
What I'm doing wrong or not doing here?
Thanks in advance for your help
PS: by the way, the socialNetwork and actors load correctly
It looks like you forgot belongsTo side of the relationship. Add
relation: DS.belongsTo('App.Relation')
to your App.Actor model.
I am trying to migrated my app to using Ember-Data as it's persistence mechanism. One thing that strikes me is that I'm not sure if it's still possible to use an arrayProxy for aggregate properties of a hasMany association. In my previous iteration I didn't have any explicit associations, just controllers tied together by specific properties. Now I'd like to take advantage of the association functionality in ember-data, but I am getting errors when I trie to bind the content of my array proxy to the "children" property of the DS.Model. My code is below and there is a jsfiddle here: http://jsfiddle.net/sohara/7p6gb/22/
The error I get is:
Uncaught TypeError: Object App.recipeController.content.ingredients has no method 'addArrayObserver'
I would like to be able to retain a controller layer, even if the data associations are controlleed at the model level. It'd also (ideally) like the child objects to be embedded in the json representation of the parent object in order to avoid multiple server requests.
window.App = Ember.Application.create();
App.store = DS.Store.create({
revision: 3,
adapter: DS.fixtureAdapter
});
App.Ingredient = DS.Model.extend({
name: DS.attr('string'),
price: DS.attr('string')
});
App.Recipe = DS.Model.extend({
name: DS.attr('string'),
ingredients: DS.hasMany('App.Ingredient', {embedded: true} )
});
App.Recipe.FIXTURES = [
{id: 1, name: 'Pizza', ingredients: [{id: 1, name: 'tomato sauce', price: 2, recipeId: 1}]}
];
App.recipeController = Ember.Object.create({
content: App.store.find(App.Recipe, 1)
});
App.ingredientsController = Ember.ArrayProxy.create({
content: 'App.recipeController.content.ingredients',
totalWeigth: function() {
var price = 0;
items = this.get('content');
items.forEach(function(item) {
weight += price;
});
}.property()
});
In App.ingredientsController you need to have contentBinding: 'App.recipeController.content.ingredients', instead of content: ...