Backbone update nested collection with ids. (Rails Backend) - ruby-on-rails

I have a model appointment which has many tasks.
Creating a new appointment model which has tasks works fine with backbone. But when i try to update the model with the ids of different tasks it is not working.
I get the following error:
ActiveRecord::AssociationTypeMismatch: Task(#1192000) expected,
got ActiveSupport::HashWithIndifferentAccess(#2458300)
Parameters:
{"appointment"=>
{"id"=>"36",
"customer_id"=>"19",
"employee_id"=>"10",
"done"=>"",
"notes"=>"",
"starts_at"=>"2012-09-05 13:00:00 +0200",
"ends_at"=>"2012-09-05 14:30:00 +0200",
"bookingtype"=>"",
"tasks"=>
"[{\"created_at\"=>\"2012-09-04T13:37:17+02:00\",
\"duration\"=>\"60\", \"id\"=>\"12\",
\"task_category_id\"=>\"5\", \"updated_at\"=>\"2012-09-04T13:46:13+02:00\"}]",
"appointment"=>"",
"task_ids"=>"[\"12\"]"},
"action"=>"update",
"controller"=>"appointments",
"id"=>"36"}
I have some idea that the problem is that there is tasks and task_ids in the request but I have no idea how to fix that in backbone.
My update method looks like this:
save: function() {
var self = this;
var tasks = [];
$("input:checked").each(function() {
tasks.push($(this).val());
});
this.model.save({starts_at: this.$('#appointment_starts_at_modal').val(), employee_id: this.$('#employeeSelect').val(), customer_id: this.$('#customerSelect').val(),
"starts_at(5i)": this.$('#appointment_starts_at_5i_modal').val() ,
"ends_at(5i)": this.$('#appointment_ends_at_5i_modal').val(), task_ids: tasks}, {
success: function(model, resp) {
self.model = model;
self.close();
},
error: function() {
//new App.Views.Error();
}
});
return false;
},

From the error, it sounds like a ruby issue and I'm not familiar with ruby at all. But, with respect to Backbone, it shouldn't be a problem that you have a "tasks" and "task_ids" attribute in your appointment model. Backbone will happily send those over to your server as JSON data. Note however, that when working with nested collections in Backbone, the way you're passing the ids as an attribute outside of the task models is a bit odd. :-)
I can talk a little bit about what I see from a Backbone perspective though.
I'm assuming your tasks_ids attribute represents an array of ids of all the tasks you have. tasks is an array() of task JSON objects. In Backbone, when working with nested collections and such, usually the id attribute of each task would be part of the task object. So if I made an app that sent a bunch of tasks data as an array, it would send looking like this:
"tasks"=>
"[{\"id"=>\"12\", \"created_at\"=>\"2012-09-04T13:37:17+02:00\",
\"duration\"=>\"60\", \"id\"=>\"12\",
\"task_category_id\"=>\"5\", \"updated_at\"=>\"2012-09-04T13:46:13+02:00\"}]",
When I work with nested collections I basically make sure the ids and all attributes of some model are encapsulated by the object.
// My fake JSON
{'id':'1', 'appointment':{
'id':'50',
'tasks':[
{'id':'100', 'taskName':'groceries' /* etc. */},
{'id':'200', 'taskName':'bank errand'}
]
}}
When my appointment model receives this fetched data, I'll either process it in my parse() or modified set() method. I'll just demonstrate what I do with parse()
// Inside my appointment model definition
parse: function(response) {
if (_.isUndefined(this.tasks)) {
this.tasks = new TasksCollection();
}
this.tasks.reset(response.tasks);
delete response.tasks;
return response;
}
Something like the above. My TasksCollection would have model: Task defined so resetting with an attributes hash will populate my collection nested inside my appointment model with the appropriate data (with ids included.)
I don't think this solves your problem, but since you were alluding to the Backbone way of doing things I thought having this way (among many) illustrated might give you some ideas.

Related

Strategy for mapping locally created core data objects to webserver and back

I'm trying to devise a solution to use across many models for mapping locally created nested relationships to the server and back. Consider that I have the following models:
Order
LineItem
Payment
An Order has many line items and payments.
If I create an order locally, send it to server, I can map the id attribute assigned by the server no problem, as I am working on the same object. However, my dilemma revolves around submitting nested attributes to the server. Consider this:
I create an Order and Payment locally, and send to the server's REST endpoint for Order
{"email":"test#gmail.com", payments_attributes: [{"amount": 15.50}, {"amount": 12}]}
And I receive a JSON response with something like:
{"id": 10, "email":"test#gmail.com", payments_attributes: [{"id": 50, "amount": 15.50}, {"id": 51, "amount": 12}}
What's a good strategy for mapping these nested payment id attributes back to the correct Core Data object? I can obviously check things like payment amount, but thats brittle (imagine the edge cases!), and works only for the payment model. I need a generalized solution to use for many different models. The only thing I can think of is to create a UUID locally, send it up, and have the server push it back along with the id, but that requires a lot of patching on the server side and I hate the idea of the client managing unique attributes. My backend is Rails and I want this working with minimal (if any) changes to the server side.
I've been previously using RestKit, and it magically worked (I think it nuked the local objects and created new ones) but I am working towards dropping that dependency and doing the mapping myself... for performance and control reasons.
It sounds like you already know what you need to do.
With the current server API, you can only match up data by looking at values. Since they're not guaranteed to be unique, the results of matching them are not guaranteed to be reliable.
If you send some unique ID to the server, which returns it, then you have a unique key that unambiguously matches your outgoing data to the new incoming data. The server doesn't need to store this ID or do anything else with it-- it just needs to make sure to take the incoming ID and include it with the outgoing result data. It doesn't even matter if multiple clients have the same unique IDs, since all they're doing with them is matching outgoing server data to returned data.
Here is the solution I've come up with.
Server Modifications
Add a Ruby Mixin to all ActiveRecord::Base classes that will utilize this
Create a reusable base template for rendering JSON
Mixin
module CoreDataIdentification
extend ActiveSupport::Concern
included do
attr_accessor :object_id
end
end
And to use it:
class LineItem < ActiveRecord::Base
include CoreDataIdentification
end
Or simply (in an initializer):
ActiveRecord::Base.send :include, CoreDataIdentification
Easy enough! This works well, because the ID is not persisted to the server database, it simply passes back whatever it was given.
JSON Template (using the RABL gem)
attributes :id
attributes :object_id, if: lambda {|object| object&.object_id }
node(:errors) { |object| object.errors }
node(:created_at) {|object| object.api_timestamp(:created_at) }
node(:deleted_at) {|object| object.api_timestamp(:deleted_at) }
node(:updated_at) {|object| object.api_timestamp(:updated_at) } if locals[:index]
node(:errors) { |object| object.errors } if locals[:errors]
Example order.rabl
object #line_item
extends('base', locals: {index: locals[:index], errors: locals[:errors]})
attributes :order_id, :price, :adjustment_total, :promo_total, :additional_tax_total, :included_tax_total, :additional_service_fee_total, :included_service_fee_total, :quantity, :variant_id, :currency, :pre_tax_amount
Client side code (Objective-C)
Subclass NSManagedObject to serve as a template for managing commonly shared attributes between all models (id, object_id, created_at, etc)
Method: Serialize core data attributes to JSON
Method: Map JSON attributes to Core Data
Method: Map JSON relationships to Core Data
Some sample code that I am still playing with:
- (NSMutableDictionary *)requestParams
{
NSMutableDictionary *params = [NSMutableDictionary dictionary];
if (self.id)
params[#"id"] = self.id;
else {
params[#"object_id"] = self.objectID.URIRepresentation.absoluteString;
}
return params;
}
And to map the relationships:
- (void)mapRelationships:(NSDictionary *)JSON
{
[self connectKeyPath:#"line_items" dict:JSON entity:#"LineItem"];
[self connectKeyPath:#"payments" dict:JSON entity:#"Payment"];
//[self connectKeyPath:#"adjustments" dict:JSON entity:#"Adjustment"];
}
+ (GMManagedObject *)objectFromURL:(NSString *)URL inContext:(NSManagedObjectContext *)context
{
NSURL *url = [NSURL URLWithString:URL];
NSManagedObjectID *objectID = [[GListManager shared].managedObjectStore.persistentStoreCoordinator managedObjectIDForURIRepresentation:url];
return [context objectWithID:objectID];
}
- (void)connectKeyPath:(NSString *)keyPath dict:(NSDictionary *)JSON entity:(NSString *)entityName
{
NSArray *items = [JSON objectForKey:keyPath];
for (NSDictionary *item_attributes in items) {
NSString *object_id = [item_attributes objectForKey:#"object_id"];
NSNumber *id = [item_attributes objectForKey:#"id"];
GMManagedObject *item;
if (object_id) {
// find local
item = [self.class objectFromURL:object_id inContext:self.managedObjectContext];
} else {
item = [self findOrCreateByEntity:entityName andId:id];
}
[item mapResponse:item_attributes];
}
}
I still have a lot of work to do in refactoring this for flexibility and performance... but I think this is a step in the right direction... rendering thousands of lines of RestKit code moot.

Ember.js route for the current user's /settings page

A common pattern for a user's settings page would be for it to live at /settings.
In my Rails app, I'm accomplishing this on the API side by mapping get 'settings' to Settings#show and looking for the current_user's settings.
But on the Ember side, I'm stumped. There's no ID to use for the GET request, so I can't use the typical pattern of this.store.find('setting', params.id) within my route.
What's the "Ember way" of handling this sort of use case?
This has been discussed here: http://discuss.emberjs.com/t/fetching-single-records/529/3
The issue with loading a single record not based on an ID, is that you need to get back a DS.Model object as a promise. If you get back a record that's already in the client's memory you would now have two different objects representing the same record (type and id combination). Take this example:
var user123 = App.User.find(123);
var currentUser = App.findByUrl('/users/current'); //This is an imaginary method, i.e. Ember Data don't support it
notEqual(user123, currentUser, "The user objects can't be the same cause we don't know what the current user is yet");
Now we get this response from the server:
{
"user": {
"id": 123,
"name": "Mufasa"
}
}
Now currentUser and user123 both have id 123, but they are essentially different objects = very bad. This is why this approach wouldn't work.
Instead you will want to load a record array of users, listen for it to load, and then take the firstObject from the loaded records. Like this:
var users = App.User.find({ is_current: true });
users.one('didLoad', function() {
App.set('currentUser', users.get('firstObject');
});
$.ajax({
type: 'GET',
url: '/users/current',
success: function(payload) {
var store = this.store;
var userReference = store.load(App.User, payload.user);
App.set('currentUser', store.recordForReference(userReference));
}.bind(this)
});

Mongo and Node.js: unable to look up document by _id

I'm using the Express framework and Mongodb for my application.
When I insert objects into the database, I use a custom ObjectID. It's generated using mongo's objectid function, but toString()ed (for reasons i think are irrelevant, so i won't go into them). Inserts look like this:
collection.insert({ _id: oid, ... })
The data is in mongo - i can db.collection.find().pretty() from mongo's cli and see it exactly as it's supposed to be. But when I run db.collection.find({_id: oid}) from my application, I get nothing ([] to be exact). Even when I manually hardcode the objectID that I'm looking for (that I know is in the database) into my query, I still can't get an actual result.
As an experiment, I tried collection.find({title: "test title"}) from the app, and got exactly the result I wanted. The database connection is fine, the data structure is fine, the data itself is fine - the problem is clearly with the _id field.
Query code:
var sid = req.param("sid");
var db = req.db;
var collection = db.get("stories");
collection.find({'_id': sid }, function(err, document) {
console.log(document.title);
});
Any ideas on how I can get my document by searching _id?
update: per JohnnyHK's answer, I am now using findOne() as in the example below. However, it now returns null (instead of the [] that i was getting). I'll update if I find a solution on my own.
collection.findOne({'_id': sid }, function(err, document) {
console.log(document);
});
find provides a cursor as the second parameter to its callback (document in your example). To find a single doc, use findOne instead:
collection.findOne({'_id': sid }, function(err, document) {
console.log(document.title);
});

Jersey POST operation with PathParam and JSON Object

By design, GET operation should be used only for read Only operation. Howeevre,i am looking for a plausible way of implementaion of following.Implement a POST operation that can be called as it is mentioned below
POST /my-store/order/D : where D is the day the customer place an order
Request: POST /my-store/order/14
{
"customer" : "XYZ",
"order" : {
"item1" : 2
}
}
I tried implementing using below function
#Path("/D")
#POST
#Consumes({ MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
public Response submitOrder(#PathParam("D") int elapsedDays, #Context UriInfo uriInfo, Order orderInfo){
..........
}
But the above implementation does not seem to working. When I try to test the implementation using MyEclipse REST explorer ,it does not offer option to pass in Order object but allow 'D' parameter only. However, if #PathParam and #Path is removed then it works perfectly fine i.e. allows to consume JSON Order object.
But,the requirement is to pass the days as Path parameter and Order object as JSON input in POST request.
Looking for suggestion on implementation approach and design approach.
Thanks in advance
For one thing, your path should be configured like this:
#Path("/{D}")
I assume your extended ellipses means you have some method parameter that represents the deserialization of your order.

form serialize problem

I have a form. I am trying to validate it through AJAX GET requests.
So i am trying to send the field values in the GET request data.
$('#uxMyForm').serialize();
the problem it is returning something undecipherable. I have used serialize before. This is totally bizzare.
the return value of serialize is
actionsign_upcontrollersitedataauthenticity_token=oRKIDOlPRqfnRehedcRRD7WXt6%2FQ0zLeQqwIahJZJfE%3D&customer%5BuxName%5D=&customer%5BuxEmail%5D=&customer%5BuxResidentialPhone%5D=&customer%5BuxMobilePhone%5D=&customer%5BuxDateOfBirth%5D=&customer%5BuxAddress%5D=&customer%5BuxResidentialStatus%5D=
i have no idea how to use this.
Thanks
update:
My question is how do i process such a request? like this?
puts params[:data][:customer][:uxName]
my GET request trigger looks like this
$.get('/site/sign_up',{data : $('#uxMyForm').serialize() }, function(data){
alert(data);
});
The above jquery lines generate the request.. on the action method i do the following
render :text => params
when i observe what is sent in the GET,in firebug PARAMS
**data** authenticity_token=oRKIDOlPRqfnRehedcRRD7WXt6%2FQ0zLeQqwIahJZJfE%3D&direct_customer%5BuxName%5D=&direct_customer%5BuxEmail%5D=&direct_customer%5BuxResidentialPhone%5D=&direct_customer%5BuxMobilePhone%5D=&direct_customer%5BuxDateOfBirth%5D=&direct_customer%5BuxAddress%5D=&direct_customer%5BuxResidentialStatus%5D=
the return value that i print in alert has
actionsign_upcontrollersitedataauthenticity_token=oRKIDOlPRqfnRehedcRRD7WXt6%2FQ0zLeQqwIahJZJfE%3D&direct_customer%5BuxName%5D=&direct_customer%5BuxEmail%5D=&direct_customer%5BuxResidentialPhone%5D=&direct_customer%5BuxMobilePhone%5D=&direct_customer%5BuxDateOfBirth%5D=&direct_customer%5BuxAddress%5D=&direct_customer%5BuxResidentialStatus%5D=
How does the form itself look. I have no experience with Ruby on rails - and if it builds the form in a new exciting way - but it looks as if there's only two form elements: authenticity_token and customer - where customer is an array of items. This is the data you posted, but I urldecoded it and put in some linebreaks:
authenticity_token=oRKIDOlPRqfnRehedcRRD7WXt6/Q0zLeQqwIahJZJfE=
&customer[uxName]=
&customer[uxEmail]=
&customer[uxResidentialPhone]=
&customer[uxMobilePhone]=
&customer[uxDateOfBirth]=
&customer[uxAddress]=
&customer[uxResidentialStatus]=
What you could do is to serialize the form to an array and clean it up before sending it using jQuery ajax request. I did something similar once when I had to serialize .net runat-server form elements:
var serializedData = $(form).serializeArray();
for( i=0; i < serializedData.length; i++)
{
// For each item in the array I get the input-field name after the last $ character
var name = serializedData[i].name;
var value = serializedData[i].value;
if( name.indexOf('$') != -1)
name = name.substr( name.lastIndexOf('$')+1 );
serializedData[i].name = name;
}
var ajaxPostData = $.param(serializedData);
So instad of blabla$ABCPlaceHolder$tbxEmail I got tbxEmail in the array. You could do the same to get uxName, uxEmail etc instead of the customer array.
Note then again, however, due to my inexperience with ruby that this may not be the best solution - maybe there's a setting you can change to build the HTML form differently?
Updated:
I'm not sure how ruby works, but after a googling I found you should be able to receive your values using params:customer as an array.
params:customer should contain an array of the values
{:uxName => "", :uxEmail => "" }
I hope that tells you something on how to receive the data. Maybe (warning - wild guess!) like this?
params[:customer][:uxName]

Resources