backbone relational not updating - javascript

I have a relationship setup between my user object and my usergame object.
The relationship appears to be setup correctly, i can access usergames through a user object.
However, when I create a new usergame object, the user object does not update.
Could someone offer me a solution to this?
Relationship is setup like so:
class App.Models.User extends Backbone.RelationalModel
urlRoot: '/user'
relations: [
type: Backbone.HasMany
key: 'user_games'
relatedModel: 'App.Models.UserGame'
includeInJSON: true
collectionType: 'App.Collections.UserGames'
reverseRelation:
key: 'user'
]

From the documentation:
Q: (Reverse) relations or submodels don't seem to be initialized
properly (and I'm using CoffeeScript!)
A: You're probably using the syntax class MyModel extends
Backbone.RelationalModel instead of MyModel =
Backbone.RelationalModel.extend. This has advantages in CoffeeScript,
but it also means that Backbone.Model.extend will not get called.
Instead, CoffeeScript generates piece of code that would normally
achieve roughly the same. However, extend is also the method that
Backbone-relational overrides to set up relations and other things as
you're defining your Backbone.RelationalModel subclass.
That’s a shame, as I like Coffeescript’s extend syntax. Try it without, as explained in the documentation?

Related

Multiple polymorphic relationships in Ember (Octane) models and Mirage

In our Rails backend, we have a lot of Concerns server side. For example, several models import an AppointableConcern which allows the resources to be associated with Appointments. Each model can import an unlimited number of Concerns.
In our Ember Octane models, we use inheritance instead, and I'm not sure whether that's a good idea. For example, we have these two models...
// models/groupable.js
import { belongsTo } from '#ember-data/model';
import ApplicationModel from './application'
export default ApplicationModel.extend({
group: belongsTo('group', { inverse: 'groupables' }),
});
// models/appointable.js
import { hasMany } from '#ember-data/model';
import Groupable from './groupable';
export default Groupable.extend({
appointments: hasMany('appointment')
});
... as well as some models extending either Appointable or Groupable.
To me it seems inheritance has been abused to share logic between classes that are not closely related: An Appointable is not a specific implementation of a Groupable (multiple Groupables can form a Group) at all.
Now I wonder:
Is this a recommended/standard way to share this logic between models?
Is there a more flexible alternative? Considering my example above, directly using group: belongsTo('group', { inverse: 'groupables' }) in any model that should be groupable and appointments: hasMany('appointment') in all models that appointments should be allowed to associate with seems like a simple solution.
edit:
We encountered a problem with the solution i sketched out above. It is related to EmberCLI Mirage tests: I wanted to make one more model groupable, but it does not fit in the inheritance chain well. We couldn't make it inherit from the Groupable model. So we added this line directly to the new model: group: belongsTo('group', { inverse: 'groupables' })
This works in the browser, but in Mirage I got this error:
The 'article' type does not implement 'groupable' and thus cannot be assigned to the 'groupables' relationship in 'group'. Make it a descendant of 'groupable' or use a mixin of the same name.
But as there is no multiple inheritance, I can't make Article a descendant of Groupable and there are no mixins in Mirage at all. So I removed { inverse: 'groupables' } from my new model, which is ok for the moment, but we shouldn't need to take away functionality from our code just to make a test work.

What to use for data-only objects in TypeScript: Class or Interface?

I have a bunch of data-only "classes" (in .NET world we call them POCO objects) that does not have any methods or even constructors. Examples are Customer, Product, User entities, you name it...
Originally I started using typescript classes but now I'm thinking that declaring them as interface might be better. From performance standpoint, and not only... It's just that in C# we're used to use interfaces for different thing, and for "POCO" (Plain-old-clr-object, or "data-only" object) we use just a class (sometimes even struct).
What is a proper way to declare them in TypeScript?
Note that I mostly understand (I think) technical differences between class and interface (i.e. that interface is a compile-time construct), but I'm trying to find out which one fits this case semantically.
P.S.: I've seen similar questions (like this) but none of them adress this specific issue clearly and definitely, so please don't close this as 'possible duplicate' or 'opinion-based' (cause it isn't) :)
Interface and it's not even close.
People start writing TypeScript and they suddenly think they have to use classes for some reason. But they don't. Classes are an ES6 feature and they work fine, but if it's just data, it's just data.
A major problem with using classes is that they won't serialize/deserialize like you expect over the wire, so things like instanceof checks won't work.
One rule of thumb is that if there's not internal state associated with some methods, and there's no need for traditional OO polymorphism, don't use a class. This even extends to static classes -- use namespace / module instead.
Use classes with parameter properties:
// Immutable data object
class Person {
constructor(readonly firstName: String, readonly lastName: String) {}
}
// Mutable data object
class Person {
constructor(public firstName: String, public lastName: String) {}
}
I use classes for my data in Typescript, as I allways did in C# C++ Java, and only use interfaces for dependency injection. Interfaces have not be thought for manipulating data.
In my application model, if I need to write a method that uses some datas of the same class, then the class is better place to go for that method. Adding getters and setters that transform your properties is a great flexibility.
I am not a javascript programmer so when I need to create an object, I don't like using data only object where properties can by anything. I create an instance of class by the way of the constructors that have been defined for that class.
When I receive data from a service, I don't deserialize a class: I deserialize the json data and I create my instance with that data. Here is the way for building my model from the received data:
// ajax callback for diaries
onReceiveDiary( jsonDiary : any )
{
let newDiary = new Diary ( jsonDiary );
// now I can call methods on the object:
let ok : boolean = newDiary.CheckIfCompleted();
}
In the class I add a constructor with the only one dependency on the json object:
export class Diary
{
title : string;
article : Article;
constructor( json : any )
{
// the trick for setting all the object properties
$.extend( this, json);
this.article = new Article( json.article );
}
}
Or we can create a factory for building objects using the default constructor:
let newDiary = new Diary ();
$.extend( newDiary, jsonDiary );
newDiary.article = $.extend( new Article(), jsonDiary.article );

Load includes on existing model

I'm trying to load includes on an existing model in sequelize. In express we pre check the models to see if they exist in the middleware.
So once we're in the actual "controller" we want to run some includes on that existing model that is passed in.
req.models.item.incude([
{model: Post, as: 'posts'}
])
Is there any way to accomplish this?
EDIT:
I know we can do something like this.
return req.models.item.getThing()
.then(function (thing) {
req.models.item.thing = thing;
return req.models.item;
});
But:
My expansions for includes are a dynamic property that come via url parameters, so they are not know ahead of time.
It I return the above you will not see the "thing" in the response. I need it nicely built as part of the original instance.
Something like a .with('thing', 'other.thing'); notation would be nice. Or in the case of sequelize .with({include: ...}); or .include([{model: ...}]);
If the variable req.models.item is already an Instance but without its other related instances ("includes"), then you could include them using something like the following code:
Item.findAll({
where: req.models.item.where(),
include: [{
model: SomeAssociateModel,
}]
})
.then(function(itemWithAssoc) {
// itemWithAssoc is an Instance for the same DB record as item, but with its associations
});
See here for some documentation. See here for a script demo'ing this.
Update: Given the instance, how do I just get the associated models?
To do this just use the automatically generated "getAssociation" getter functions, e.g.:
function find_associations_of_instance(instance) {
return instance.getDetails();
}
I've updated the script to include this as an example. For more information on these functions, see the SequelizeJS docs.

Backbone.js What is the purpose of specifying a model in collection

Here is what I am trying to understand.
Often times I find myself writing backbone like this:
var CallModel = Backbone.Model.extend({
});
var CallsCollection = Backbone.Collection.extend({
model: CallModel,
url: 'url/to/external/json'
});
It is a very basic example but as you can see, there is nothing really in the model all the data is coming into the Collection via an external url call to a json file that is build from a database.
So whats the purpose of the model? I am sure that I am probably not using backbone.js to its fullest extent which is why I am here asking you guys.
First of all, "there is nothing really in the model all the data is coming into the Collection via an external url call" - this is not true.
Let's assume you've the following:
//Model
var CallModel = Backbone.Model.extend({
defaults: {
cost:0,
duration:0
}
});
(without custom attributes or methods, there is no point in extending the original Backbone.Model)
//Collection
var CallsCollection = Backbone.Collection.extend({
model: CallModel,
url: 'url/to/external/json'
});
And the json data returned from service, probably something like:
//Response
{
callSummary: {
missed: 2,
received: 3,
totalCalls:5
totalDuration: 20
}
calls: [{
id:001,
caller:"Mr.A",
callee:"Mr.B",
cost:1,
duration:5
},{
id:002,
caller:"Mr.X",
callee:"Mrs.Y",
cost:1,
duration:7
},{
id:003,
caller:"Mr.A",
callee:"Mrs.B",
cost:1,
duration:8
}],
//and more additional information from your db
}
Now you populate your collection with data by calling it's fetch method:
CallsCollection.fetch();
Your collection should look something like:
{
models: [{
attributes: {
callSummary: {},
calls: [{},{},{}],
...
},
...
}],
length:1,
url: "url/to/external/json",
...
}
The data will be added to a model's attribute hash. If you don't specify a particular model, as Bart mentioned in his answer, backbone will populate the collection with a Backbone.Model instance: Which is still not much useful - Wew... A collection with single model having entire response data inside it's attributes as it is...
At this point, you're wondering why did I even bother creating a model, and then a collection..?
The problem here is Collections are derived from Arrays, while Models are derived from Objects. In this case, our root data structure is an Object (not an Array), so our collection tried to parse the returned data directly into a single model.
What we really want is for our collection to populate its models from the "calls" property of the service response. To address this, we simply add a parse method onto our collection:
var CallsCollection = Backbone.Collection.extend({
model: CallModel,
url: 'url/to/external/json',
parse: function(response){
/*save the rest of data to corresponding attributes here*/
return response.calls; // this will be used to populate models array
}
});
Now your collection will be something like the following:
{
models: [{
...
attributes: {
...
id:001,
caller:"Mr.A",
callee:"Mr.B",
cost:1,
duration:5
}
},{
...
attributes: {
...
id:002,
caller:"Mr.X",
callee:"Mrs.Y",
cost:1,
duration:7
}
},{
...
attributes: {
...
id:003,
caller:"Mr.A",
callee:"Mrs.B",
cost:1,
duration:8
}
}],
length:3,
url: "url/to/external/json",
...
}
This - is what we want! : Now it is very easy to handle the data: You can make use of the add, remove, find, reset and handful of other collection methods effectively.
You can pass this models array into your templating library of choice, probably with two way bindings: When the respective view for one of the call model changes, the particular model will be updated, events will propagate from your models to the collection, and the particular model will be passed into the handler functions.
You can now call fetch, save, destroy, clear and a lot of other methods with ease on single unit's of data (each model), rather than hurdle with the entire data saved in a single model - which is pretty much useless, you've to iterate through the response data manually and perform CRUD and similar operations by your own, and in most cases: re-render the entire collection view. which is very, very bad and totally unmaintainable.
To conclude: If your data source doesn't return an array of objects, or you don't parse the response and return an array of objects from which n number of models are to be populated - Then defining a collection is pretty much useless.
Hopefully, now you get the idea.
Very helpful source of info:
Backbone, The Primer: Models and Collections
Developing Backbone.js Applications
backbonejs.org
You don't need to specify a model. A Backbone collection will default to using Backbone.Model if you don't specify this option. The following would work equally well if you don't need the models of the collection to be of a particular instance.
var CallsCollection = Backbone.Collection.extend({
url: 'url/to/external/json'
});
Reference
EDIT
In essence, specifying the model option within a collection is just a way to ensure that objects added to this collection will be instances of that particular model class. If the models being added to your collection don't have any custom behaviour outside of what is available to Backbone.Model, you don't need to create and specify a model as Backbone collections will default to using an instance of Backbone.Model as I have already mentioned. If, however, you wanted to ensure that models added to a particular collection were of a particular type and shared customized behaviour (e.g. validations, defaults, etc.), you would create your own model class by extending Backbone.Model and specifying this in the collection. I hope this clears things up for you.
Sounds Weird but this is the way.
Every collection in backbone, must represent a model, so basically a collections is a list of models.
Even if your model has no data, you need to indicate it when you create a Collection.
This is how backbone works for collections.

Using BackFire.js with Chaplin.js

I want to use Firebase's backfire.js in my chaplin.js application.
Is it possible to use both Chaplin.js Collection and backfire.js Collection?
Maybe extending the Chaplin.js Collection and using the backfire.js Collection as a mixin, something like this?
Chaplin = require 'chaplin'
Model = require 'models/base/model'
BackBone = require 'backbone'
module.exports = class Collection extends Chaplin.Collection
_(#prototype).extend BackBone.FireBase.Collection
model: Model
Firebase seems to add itself to the Backbone object, in the above example how I should reference it from my code?
[Update]
Backfire's special Firebase Collection object makes several references to Backbone.Collection, which tripped me up for awhile. I replaced this special object entirely to overwrite these references, but there's probably a much better way that my fragile mind cannot yet handle.
..a gist! https://gist.github.com/dustinlarimer/6800730
[Prev]
One quick observation.. drop the 2nd syllable capitalization on Backbone and Firebase:
_(#prototype).extend Backbone.Firebase.Collection
You also shouldn't need to include Backbone:
Model = require 'models/base/model'
module.exports = class FirebaseModel extends Model
_(#prototype).extend Backbone.Firebase.Model
initialize: ->
console.log 'init FirebaseModel'
super

Categories

Resources