Backbone-relational: Association key won't work unless it's the same as the foreign key - javascript

I'm trying to get the backbone-relational plugin working with an association between tasks and messages. (A task has many messages).
The information is pulled from a standard rails/activerecord site, which has a task_id field as the foreign key.
The problem is, backbone-relational won't populate the 'messages' field with any messages on teh Task model unless I set the key as "task_id" in the reverse relation...but that means that, when accessing the task from the Message model, the task_id field is populated with the actual task object, not the 'task_id' integer, which is overwritten.
I'm guessing there's a simple way to specify task_id as the foreign key with which to determine the parent task, yet have the object that key represents placed in a different field (eg 'task' on the messages object)...but I can't figure out how. Any ideas appreciated. Code below
class Backbonescaffolddemo.Models.Task extends Backbone.RelationalModel
paramRoot: 'task'
relations: [{
type: Backbone.HasMany,
key: "messages",
relatedModel: "Backbonescaffolddemo.Models.Message",
collectionType: "Backbonescaffolddemo.Collections.MessagesCollection",
includeInJSON: true
reverseRelation: {
key: "task_id"
includeInJSON: true
}
}]

You may be able to use keySource or keyDestination to address your particular problem.
Example
In the following example, suppose we are getting data from an old-school relational database, where there is a one-to-many relationship between Monster and Loot_Item. This relationship is expressed by a Monster_Id foreign key in the Loot_Item table. Let us also suppose that our REST service doesn't do any fancy-pants data nesting for us, since that seems to match the situation in your question fairly closely.
keySource
Now, let's set set "keySource" to my foreign key ("Monster_Id") and "key" to the name of the attribute where I want the actual data to go (say, "Monster"). If you break in the debugger, you will see in the attributes object that there is, in fact, a field called "Monster", and that it does point to the monster model data. Hey, cool!
includeInJSON
However, if you toJSON that puppy, guess what? It has put all the monster data in Monster_Id, just like you didn't want! GAH! We can fix that by setting "includeInJSON" to "Monster_Id". Now, when it is converted to JSON, it puts the proper ID back into the Monster_Id field, when it is serializing your data to JSON, to send up to the server.
Problem solved? Er, well, actually, not necessarily...
CAVEAT: This all sounds super-useful, but there's one fairly glaring problem that I have found with this scenario. If you are using a templating engine (such as the one in Underscore.js) that requires you to convert your model to JSON, before passing it into the template, whoops -- you don't have access to your relational data. Alas, the JSON that we want for our messages is not necessarily the same JSON that we want to feed into our templates.

If you want the "task_id" in the message JSON to be the id, not the full JSON for the task, then set the "includeInJSON" to be the Task's ID property ("task_id")
class Backbonescaffolddemo.Models.Task extends Backbone.RelationalModel
paramRoot: 'task'
relations: [{
type: Backbone.HasMany,
key: "messages",
relatedModel: "Backbonescaffolddemo.Models.Message",
collectionType: "Backbonescaffolddemo.Collections.MessagesCollection",
includeInJSON: true
reverseRelation: {
key: "task_id"
includeInJSON: "task_id"
}
}]
The "true" value for includeInJSON says to use the full JSON for the related model.
Edit: After re-reading your question, I'm not sure my answer relates to your issue.
My original answer is for posting a message back to the server where you want the JSON to be something like:
{
"message_title": "My Title",
"message_body": "Blah blah blah...",
"task_id": 12345
}
I'm not sure what exactly you're looking to happen, but the way that Backbone Relational is supposed to work is that the Task's collection of messages will be a collection of the full models, so you can iterate over them and pass them to views for rendering, etc.
If you want to output one of the Message's id's in a template or something, then you'd take the Message model's "id":
myTask.get('messages').first().id -> returns the first message's id

Related

Getting control over positioning of v-for items

Im working on a information-management system (vuejs, postgresql, graphql/hasura) for my company at the moment. We work project-based and have a lot of information to handle. Using postgresql, I've set up a few tables, ex client_information, general_information, internal_information and so on. (see structure below)
title -----| value | completed | date | project_number
-------------------------------------------------
customer -- walmart -- true ----- xx ----- 19823 --
contact --- xxxxxx --- false ---- xx ----- 19823 --
email ----- xxxxxx --- false ---- xx ----- 19823 --
So, this table with client_info contains info about all the clients we have, and each row is connected to a project by it's project number (19823). So, using hasura(graphQL) I make a request that returns all information about a chosen project in the form of a array filled with objects:
[ { title: 'customer', value: 'walmart', completed: true,
date: 'xx' project_number: 10823 }, {...}, {...}, {...} ]
So far all is fine and dandy, I could just v-for through the entire array and spit out all the information I need.
BUT, I'd like to be able to control in which order the items are displayed. During testing I created a function that takes in the array of objects above, and an array that I specify on the client looking like this:
['email', 'customer', 'contact']
This orders the array of items in the order specified, and works, but feels.. weird?
Consider this example:
This is my array:
const arr = [
{title: "customer", value: "walmart"},
{title: "email", value: "xx#xx.xx"},
{title: "phone", value: "01234"}
];
Then I do a:
<li v-for="item in arr">, text-field(vuetify) with placeholder="item.title", and v-model="item.value" </li>
That prints out the 3 items in the order of the array, so customer first, then email, then phone. What I don't understand is how to arrange the order of items. Maybe I want phone first, with a v-for loop, how is that possible? And yes, the array is way longer than just 3 items.
It might be that it's my first time using a relational database and my lack of experience is messing me up, but with the old database (firebase) everything was quite easy since each project was stored as a separate object. If I wanted the client email I'd just link a text-field to project.customer.email, and therefore had control. For reasons we need to move to postgresql and I'm not sure how to get the same control, maybe my solution is an "okay" one even though it feels a little weird to me, I dont know.
I was thinking about indexing the items in the db but I'd like to control if from the client in case we need to make layout-changes later on.
This turned into a novel, but if any of you guys have faced a similar situation and have some tips I'd greatly appreciate them.

What is the best practice when displaying data from more than one table

I have three tables, 'sessions', 'classes' and 'schedules' which they are connected each other.
sessions: id, name, descr
classes: id, session_id, name
schedules: class_id, session_id, date
A class belongs to a session, while the schedules is a N:M relations which gives the opportunity to have particular date for each session within a single class.
My problem comes when I have to display these information, I have a function which displays all Sessions:
$sessions = Session::all();
and I have another function which displays the date of a specific class and a specific session as below:
$result = Schedule:where('class_id','=',$classId)->where('session_id','=',$essionId)->first();
So let say I have 30 sessions for a single class, when it comes to my front-end app which is written in AngularJS I dont know how to handle the displaying here using the ng-repeat iterating thru all sessions and then make another call withing the ng-repeat iteration to call the schedule to display the date of the session, this is not a good practice I guess in AngularJS.
Could anyone tell me what would be the best option for me to handle this problem? Shall I have to modify the back-end? like edit the Session:all(); query to include also the Schedule table? or what is the best way?
I supposed you have already config your relations in models, if not look here
As for me, I use Fractal to customize display data. Also there is convenient method called Available includes
So you can request your data like /sessions/?include=classes and get output
{data: [{
session_id: 1,
some: "data",
classes:[{
class_id: 11,
some: "class_data"
}]
}]}
I would "eager load" the data, so you can access all the object's parents through the object you loaded. This way you can fill your table rows one by one by just iterating over 1 object.
There is excellent documentation about eager loading at the Laravel website, so I suggest you start there

Backbone Model get attribute function returns last updated value

If there's an optional field in the server returned JSON top structure. Backbone Model seem to cache previously set value. Lets say i get a JSON like this
{
label: "test_label",
attr1: "test1",
attr2: "test2"
}
when I say #model.get("label") i get "test_label". So later on, if i get a JSON like this
{
attr1: "test1",
attr2: "test2"
}
i get "test_label" when i query for #model.get("label"). Is this a known issue in backbone.js? I do something like this to fetch
#modelXhr = #model.fetch
success: (-> this.trigger('reset')).bind #model
I'm a beginner in javascript/coffeescript, What can i do so when i query for a field which doesn't exist in the latest returned model I won't get an older value? Appreciate your help
You should either clear the model beforehand using #model.clear() or (in my opinion the better way) ensure that the data format for a specific model type does not change. Return { label: null, ... }
You are then later on able to check for the existence of the label using #model.get("label")?
If you are not able to ensure data integrity throughout your requests, clear the model.

Angular.js accessing and displaying nested models efficiently

I'm building a site at the moment where there are many relational links between data. As an example, users can make bookings, which will have booker and bookee, along with an array of messages which can be attached to a booking.
An example json would be...
booking = {
id: 1,
location: 'POST CDE',
desc: "Awesome stackoverflow description."
booker: {
id: 1, fname: 'Lawrence', lname: 'Jones',
},
bookee: {
id: 2, fname: 'Stack', lname: 'Overflow',
},
messages: [
{ id: 1, mssg: 'For illustration only' }
]
}
Now my question is, how would you model this data in your angular app? And, while very much related, how would you pull it from the server?
As I can see it I have a few options.
Pull everything from the server at once
Here I would rely on the server to serialize the nested data and just use the given json object. Downsides are that I don't know what users will be involved when requesting a booking or similar object, so I can't cache them and I'll therefore be pulling a large chunk of data every time I request.
Pull the booking with booker/bookee as user ids
For this I would use promises for my data models, and have the server return an object such as...
booking = {
id: 1,
location: 'POST CDE',
desc: "Awesome stackoverflow description."
booker: 1, bookee: 2,
messages: [1]
}
Which I would then pass to a Booking constructor, which would resolve the relevant (booker,bookee and message) ids into data objects via their respective factories.
The disadvantages here are that many ajax requests are used for a single booking request, though it gives me the ability to cache user/message information.
In summary, is it better practise to rely on a single ajax request to collect all the nested information at once, or rely on various requests to 'flesh out' the initial response after the fact.
I'm using Rails 4 if that helps (maybe Rails would be more suited to a single request?)
I'm going to use a system where I can hopefully have the best of both worlds, by creating a base class for all my resources that will be given a custom resolve function, that will know what fields in that particular class may require resolving. A sample resource function would look like this...
class Booking
# other methods...
resolve: ->
booking = this
User
.query(booking.booker, booking.bookee)
.then (users) ->
[booking.booker, booking.bookee] = users
Where it will pass the value of the booker and bookee fields to the User factory, which will have a constructor like so...
class User
# other methods
constructor: (data) ->
user = this
if not isNaN(id = parseInt data, 10)
User.get(data).then (data) ->
angular.extend user, data
else angular.extend this, data
If I have passed the User constructor a value that cannot be parsed into a number (so this will happily take string ids as well as numerical) then it will use the User factorys get function to retrieve the data from the server (or through a caching system, implementation is obviously inside the get function itself). If however the value is detected to be non-NaN, then I'll assume that the User has already been serialized and just extend this with the value.
So it's invisible in how it caches and is independent of how the server returns the nested objects. Allows for modular ajax requests and avoids having to redownload unnecessary data via its caching system.
Once everything is up and running I'll write some tests to see whether the application would be better served with larger, chunked ajax requests or smaller modular ones like above. Either way this lets you pass all model data through your angular factories, so you can rely on every record having inherited any prototype methods you may want to use.

ui-data contracts: client side extended validation of json data

I am in a few situations where json I am getting from services and database calls, created by another group, are giving me invalid data combinations, and causing many unintended errors downstream.
Given in the small example below, if the "rowContent" field is equal to "1", it's corresponding "row" needs to be a populated javascript object. "rowContent1" and "row1", and "rowContent2" and "row2" are correct. "rowContent3" and "row3" is not.
I concede the structure of this json is not fantastic. Ok it's a little wacky. It's fairly close to what I am dealing with in production. I have little control over it.
Are there data driven ways to describe json data relationships like this, that validate, before I start trying to use non-existent data in "row3"?
Or, what would you recommend I do in this situation?
thanks much,
-Larry
{ "table" : [
{
"aRowContent" : {
"rowContent1" : "1",
"rowContent2" : "0",
"rowContent3" : "1",
},
"row1" : {
"myRowValue" : "red"
},
"row2" : null,
"row3" : null
}
]
}
Not with JSON Schema, certainly. JSON Schema validates the structure of JSON data without cross-referencing to other bits of data.
I think the issue might be the redundancy in your data structure- why do you need /table/0/aRowContent/rowContent1 when you can deduce the same information from a null-check of /table/0/row1?

Categories

Resources