SailsJS blueprint matching wrong model - javascript

I'm having a tricky issue with my models and Sails' automatic blueprint matching.
When I post to one of my endpoints, /answer/create, I get a 500 response with validation errors for a different model entirely (the event model).
That endpoint for the event model would be at /event/create, but when I post to that I get a 404.
All of my files were generated with sails generate [model] and don't contain any custom Controller routes.
Has anyone seen this before?

It turned out this was a result of following this screencast:
http://irlnathan.github.io/sailscasts/blog/2013/09/15/sailscasts-answers-ep1-question-about-using-a-service-to-allow-inheritance-in-a-model/
I was inheriting a baseModel via services into more than one other model, so when I ran _.merge(), the changes it made would persist across them both, rendering inconsistencies.
If you want to do this, make sure you use the _.cloneDeep method to clone the base model, otherwise _.merge will affect it and your blueprints/actions won't work as expected.
In the screencast above, this would make line 12 in the user model look like this:
module.exports = _.merge(_.cloneDeep(baseModel) { ... });

Related

Posting to nested routes in Ember-data with the JSON API adapter

I'm using Ember-data and the JSON API Adapter, I have a particular model widgets which has a nested route /widgets/default, which when posted to will setup a default set of relationships required for adding a new 'widget'. Essentially it's a shortcut method for adding a widget and saves doing lots of posts to separate relation endpoints after creating each widget. The idea is that we want to have numerous preset types of widgets which can be created in one post, each with different sets of relationships.
I have searched the docs for Ember data but could not see anything that would allow this out of the box. Does anyone know if it's possible to use nested routes when creating a record with the JSONApi adapter?
Here's an example of what I'd like to do in pseudo code:
this.get('store').createRecord('widget.default', attrs).save().then((widget)=>{
this.get('router').transitionTo('widgets.edit', widget.id);
});
So calling createRecord on widget.default would trigger it to post the payload to the /widgets/default endpoint, rather than to /widgets.
Maybe the createRecord is what you are looking for.

Best practice to change default blueprint actions in sails.js

I'm looking for an answer to what is the best practice to customize default sails.js CRUD blueprints. The simple example of what I mean is let's say I need to create SomeModel, using standard blueprint POST \someModel action, and also I want to get information about authenticated user from req object and set this property to req.body to use values.user.id in beforeCreate function:
module.exports = {
attributes: {
// some attributes
},
beforeCreate: function (values, cb) {
// do something with values.user.id
}
};
I'm very new to sails.js and don't want to use anti-patterns, so I'm asking for inputs on what is the right way to handle such cases. Also it would be great to have some good resources on that topic.
There are a few options open to you which you've identified, and as usual, it depends on your use case. Here are some thoughts on the three options you listed in your comment:
Override controller/create - Of the three, this is the best option because it doesn't clog up code in routes or policies for a single instance.
Write controller/action and add to config/routes.js - While this works, it defeats the purpose of using blueprints, and you have to do all the code in option 1 plus making your routes code messier.
Apply a policy for a single create action - To do this, you will not only have to clutter up your /policies folder but also your policies.js file. This is more code AND it puts the logic for one controller method in two separate places, neither of which is the controller.
Out of these three, option 1 is the best because it contains the code to its context (the controller) and minimizes written code. This is assuming that you only want to alter the create method for one model.
Side note:
As an example of how your use case determines your implementation, here is how I've set my Sails app up which has a few REST routes, each of which responds differently based on the user calling the route (with a valid Facebook token):
Only uses blueprint action routes (not blueprint REST routes)
First goes through the policies:
'*': ['hasFBToken', 'isTokenForMyApp', 'extractFBUser', 'extractMyAppUser'] which store fbuser, myappuser, and other variables in req.body
At this point, my controller function (e.g. controller.action()) is called and can access information about that user and determine if it has the correct permissions to do CRUD.
Pros of this system:
All code for each CRUD operation is contained within its controller function
Minimal to no code in routes.js (no code) or policies.js (one line) or /policies
Works well with API Versioning (e.g. controllers/v1.0/controller.js), which is much easier to do with versioned controllers than versioned models. That means that I can create a new API version and simply by creating a controller in /v2.0 with a function action(), calls such as POST /v2.0/controller/action will exist with no extra routing needed.
Hopefully this example helps illustrate how design decisions were made to offer functionality like API versioning and consolidate code in its specific context.

Class methods for models with access to store

I have been battling this issue for a while now.
In my Ember app (using ember-cli) I have a model that I would like to attach some class methods for.
I would like to be able to call from my controllers Model.allWithIssues to find all of the model instances that have registered issues.
To achive that, I have added a method using the following code:
Model.reopenClass({
allWithIssues: function () { ... }
})
My problem is, I don't have access to the data store from inside the model.
I have tried in many different ways inject store:main to the model but with no luck.
One answer here even claimed there is no way to inject to a model, while others suggested ways to achieve DI into models that simply didn't work.
Is my approach completely wrong? Should I keep this logic in a separated class?
EDIT:
The solutions I had in mind are:
Make a generic controller that includes this methods and have all of the controllers that need this method extend it.
Some sort of mixin
Make a "repository" class, working as an abstraction layer between the controllers and the store.
I'm still not sure which route is the best to go in, but all of those seem too robust for something as simple as this.
Controller is not the right place either, unless you have all models loaded, and what you do its a computed propert.
the model's hook in a router would be a better place, its whitin its responsibilities of an adapter to loa data, deserialize it, and provide you with model instances.
Or you can create a service, that lives in you /lib folder, register it with the CI, and inject the store to it. depends on your use case.

JS Persistence library that will PATCH only changed values

I am evaluating JS persistence libraries. I'm on an Angular stack so ngResource and Restangular are options, but so are Breeze and Backbone's Models/collections and I'm open to others.
Is there a JS persistence library out there that will monitor changes to the model and do a PATCH of only the changed properties?
Example:
// Get a pretend user with a name, email, and some other stuff.
var currentUser = user.get(42)
// Change only the email address
currentUser.email = 'tractorDaddy#aol.com'
// Save changes
// The model could know that only one property has changed.
// The model could do a PATCH of a partial object, but I don't know a library that does.
currentUser.save()
This seems like it should be the default implementation but none of these libraries do it, that I could see.
Backbone's model decides whether to POST or PUT based on the newness of the model (determined by presence of id, as I recall). I think this is a nice move and could be extended to include PATCH.
I understand that Restangular and others have a .patch() method, but I believe in all cases you have to specify the object partial explicitly.
Is there a library that does this?
I think there is no existing JS model/persistence layer that will track and PATCH only change values.
I have high hopes for AngularJS 2.0's data layer: http://tinyurl.com/pa7rxf8

Apply Backbone.js for multi-module Javascript Website

I am writing a module based javascript website, backed by a Mysql DB.
Each module talks with the DB through PHP.
On the UI, for simplicity, the module on the left will display all relevant rows, with edit(write) functionality. The module on the right display the data from the same DB, with write access too.
So each would affect the other in each update.
I'm told backbone would be a good framework. Then, I have read the todos example, and understand how there are item->itemList, view->viewList, etc...
But now, the question is, how do I apply it to this situation?
Which is an item, a view in this situation?
The module on the left and the module on the right are Views, each of which can be made up of other views.
Within the model don't store a reference to the view (as I've seen done in some of the examples):
this.view = view; //view being passed in as an arg
The reverse (a view storing a reference to a model) is okay. Your views should be doing most of the work, listening to and responding to model events. Thus, in the view initialize method you might:
model.bind("interesting-event", function(){
//the view updates/reacts to the model.
});
Also, never add a model to two collections (just one ever). When a model is assigned to a collection, Backbone sets a reference on the model that points to the owning collection.
Incidentally, the a-model-cannot-belong-to-two-collections issue is the reason why you don't want a model referencing its view. A model can have many views on one screen.
Backbone is perfect for your needs. Start with a very basic version of your app and keep fleshing it out. All the while keep reading about Backbone online. I read everything I could find (there's not a whole lot, not really). The key concept is simply event based programming (much like you'd use in VB or lots of other platforms). It's a lot of trial and error, but you'll make sense of it with practice.

Categories