Setting Bookshelf attribute during initialization throws an error on 'this' being undefined - bcrypt

I'm seeing weird behavior regarding 'this' in a Bookshelf model and am stumped. I'm attempting to hash a password using a hook on the 'saving' event. However, if I try and get/set an attribute on 'this', it complains 'this' is undefined:
'use strict';
var DB = require('../config/db'),
_ = require('underscore'),
str = require('underscore.string'),
Base = require('./base'),
Promise = require('bluebird'),
bcrypt = Promise.promisifyAll(require('bcrypt'));
var User = DB.Model.extend({
tableName: 'users',
hasTimestamps: ['createdAt', 'updatedAt'],
// convert snake_case to camelCase
parse: function(attrs) {
return _.reduce(attrs, function(memo, val, key) {
memo[str.camelize(key)] = val;
return memo;
}, {});
},
// convert camelCase to snake_case
format: function(attrs) {
return _.reduce(attrs, function(memo, val, key) {
memo[str.underscored(key)] = val;
return memo;
}, {})
},
initialize: function() {
this.on('saving', this.hashPassword, this);
},
hashPassword: function() {
return bcrypt.genSaltAsync(10).then(function(salt){
return bcrypt.hashAsync(this.get('password'), salt);
}).then(function(hash){
this.set({'password':hash});
});
}
});
module.exports = User;
When I try and save a user model, I'm seeing the following stack trace:
Debug: internal, implementation, error
Error: TypeError: Cannot call method 'get' of undefined
at Object.exports.create (/usr/src/app/node_modules/boom/lib/index.js:21:17)
at Object.exports.internal (/usr/src/app/node_modules/boom/lib/index.js:254:92)
at Object.exports.badImplementation (/usr/src/app/node_modules/boom/lib/index.js:290:23)
at null.<anonymous> (/usr/src/app/routes/users.js:31:20)
at tryCatcher (/usr/src/app/node_modules/bluebird/js/main/util.js:24:31)
at Promise._settlePromiseFromHandler (/usr/src/app/node_modules/bluebird/js/main/promise.js:454:31)
at Promise._settlePromiseAt (/usr/src/app/node_modules/bluebird/js/main/promise.js:530:18)
at Promise._settlePromises (/usr/src/app/node_modules/bluebird/js/main/promise.js:646:14)
at Async._drainQueue (/usr/src/app/node_modules/bluebird/js/main/async.js:177:16)
at Async._drainQueues (/usr/src/app/node_modules/bluebird/js/main/async.js:187:10)
at Async.drainQueues (/usr/src/app/node_modules/bluebird/js/main/async.js:15:14)
at process._tickDomainCallback (node.js:486:13)
Any ideas?

Does this work?
hashPassword: function() {
var self = this;
return bcrypt.genSaltAsync(10).then(function(salt) {
return bcrypt.hashAsync(self.get('password'), salt);
}).then(function(hash) {
self.set({
'password': hash
});
});
}

Related

React async/await usage - Unhandled Rejection (TypeError): Cannot read properties of undefined (reading 'then')

I am adding data to an addItem array using reducers.
I want to wait until the item is actually added before going forward..I have implemented it as follows
const [addItems, dispatch] = useReducer((state, action) => {
switch (action.type) {
case 'add':
return [
...state,
{
id: state.length,
data: action.data
}
];
default:
return state;
}
}, []);
const linkDataHandler = async(samplesData, test, e) => {
const isSelected = e.target.checked;
await callDispatch(samplesData.id, test.testList.id, isSelected)
.then( r =>{
//do something
}});
};
const callDispatch = (sampleId, testId, checked) => {
const linkedData = {
sampleId: sampleId,
TestId: testId,
isSelected: checked
};
dispatch({
type: "add",
data: linkedData
});
};
function linkDataHandler is called on a checkbox onChange() event.
It is giving me
Unhandled Rejection (TypeError): Cannot read properties of undefined (reading 'then')
I have re-written callDispatch as follows. Since it is expected to return a promise
const callDispatch = (sampleId, testId, checked) => {
const linkedData = {
sampleId: sampleId,
TestId: testId,
isSelected: checked
};
return Promise.resolve(
dispatch({
type: "add",
data: linkedData
}));
};

Laravel Inertia using InertiaProgress with Axios returns: Cannot read property 'defaultPrevented' of undefined

I am using current versions of Laravel & Inertia.js. I am also using IntertiaProgress and looking to use it during a file upload using axios
The files all upload OK but the console shows:
app.js:33316 Uncaught (in promise) TypeError: Cannot read property 'defaultPrevented' of undefined
Tracing this back it points to here in the source of InertiaProgress:
start(event) {
Promise.resolve().then(() => {
if (event.defaultPrevented) {
return
}
this.inProgress++
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
Nprogress.set(0)
Nprogress.start()
}, this.delay)
})
},
If I console.log(event) I get undefined
My upload() method:
upload(files) {
let url = this.$route('library.upload');
this.$root.showLoading = true;
const uploadConfig = {
timeout: 10000,
onUploadProgress: function(progressEvent) {
let percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
InertiaProgress.progress(percentCompleted)
}
}
InertiaProgress.start()
axios.post(url, {
files,
},
uploadConfig
).then(res => {
let files = res.data.files
if (files.length) {
this.filesList = cloneDeep(files)
}
this.newFiles = []
InertiaProgress.finish()
this.$root.showLoading = false
}).catch(err => {
console.log(err)
InertiaProgress.finish()
this.$root.showLoading = false
})
},
Any help is appreciated
You could use NProgress directly.
Instead of:
InertiaProgress.progress(percentCompleted)
Like this:
NProgress.progress(percentCompleted)
See also: https://inertiajs.com/progress-indicators

Error TypeError: Cannot read property 'dispatch' of undefined at app.js:12012

Hi I've been trying to learn vuejs and vuex while trying to get response from an api call with vuex concept I got the following error.Please help.
This error occurred
Error TypeError: Cannot read property 'dispatch' of undefined
at app.js:12012
loginAction.js
export const getUsersList = function (store) {
let url = '/Apis/allUsers';
Vue.http.get(url).then((response) => {
store.dispatch('GET_USER_RES', response.data);
if (response.status == 200) {
}
}).catch((response) => {
console.log('Error', response)
})
}
loginStore.js
const state = {
userResponse: []
}
const mutations = {
GET_USER_RES (state, userResponse) {
state.userResponse = userResponse;
}
}
export default {
state, mutations
}
login.vue
import {getUsersList} from './loginAction';
export default {
created () {
try{
getUsersList();
}catch(e){
console.log(e);
}
},
vuex: {
getters: {
getUsersList: state => state.userResponse
},
actions: {
getUsersList
}
}
}
</ script>
If you call the actions manually (like in your try/catch) they'll not get the store context as the first argument. You could use getUsersList(this.store) I think, but instead I would use dispatch to reach all your actions. (I edited just a little bit to get a minimal running example, but I think you get the point!)
new Vue({
render: h => h(App),
created() {
this.$store.dispatch('getUsersList');
},
store: new Vuex.Store({
getters: {
getUsersList: state => state.userResponse
},
actions: {
getUsersList
}
})
}).$mount("#app");
Also, use commit to reach the mutations instead of dispatch. ie:
export const getUsersList = function ({commit}) {
let url = '/Apis/allUsers';
Vue.http.get(url).then((response) => {
commit('GET_USER_RES', response.data); // because GET_USER_RES is a mutation
...

Jasmine toEqual for complex objects (mixed with functions)

Currently, I have a function that sometimes return an object with some functions inside. When using expect(...).toEqual({...}) it doesn't seem to match those complex objects. Objects having functions or the File class (from input type file), it just can't. How to overcome this?
Try the Underscore _.isEqual() function:
expect(_.isEqual(obj1, obj2)).toEqual(true);
If that works, you could create a custom matcher:
this.addMatchers({
toDeepEqual: function(expected) {
return _.isEqual(this.actual, expected);
};
});
You can then write specs like the following:
expect(some_obj).toDeepEqual(expected_obj);
As Vlad Magdalin pointed out in the comments, making the object to a JSON string, it can be as deep as it is, and functions and File/FileList class. Of course, instead of toString() on the function, it could just be called 'Function'
function replacer(k, v) {
if (typeof v === 'function') {
v = v.toString();
} else if (window['File'] && v instanceof File) {
v = '[File]';
} else if (window['FileList'] && v instanceof FileList) {
v = '[FileList]';
}
return v;
}
beforeEach(function(){
this.addMatchers({
toBeJsonEqual: function(expected){
var one = JSON.stringify(this.actual, replacer).replace(/(\\t|\\n)/g,''),
two = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g,'');
return one === two;
}
});
});
expect(obj).toBeJsonEqual(obj2);
If anyone is using node.js like myself, the following method is what I use in my Jasmine tests when I am only concerned with comparing the simple properties while ignoring all functions. This method requires json-stable-stringify which is used to sort the object properties prior to serializing.
Usage:
var stringify = require('json-stable-stringify');
var obj1 = {
func: function() {
},
str1: 'str1 value',
str2: 'str2 value',
nest1: {
nest2: {
val1:'value 1',
val2:'value 2',
someOtherFunc: function() {
}
}
}
};
var obj2 = {
str2: 'str2 value',
str1: 'str1 value',
func: function() {
},
nest1: {
nest2: {
otherFunc: function() {
},
val2:'value 2',
val1:'value 1'
}
}
};
it('should compare object properties', function () {
expect(stringify(obj1)).toEqual(stringify(obj2));
});
Extending #Vlad Magdalin's answer, this worked in Jasmine 2:
http://jasmine.github.io/2.0/custom_matcher.html
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
If you're using Karma, put that in the startup callback:
callback: function() {
// Add custom Jasmine matchers.
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
window.__karma__.start();
});
here's how I did it using the Jasmine 2 syntax.
I created a customMatchers module in ../support/customMatchers.js (I like making modules).
"use strict";
/**
* Custom Jasmine matchers to make unit testing easier.
*/
module.exports = {
// compare two functions.
toBeTheSameFunctionAs: function(util, customEqualityTesters) {
let preProcess = function(func) {
return JSON.stringify(func.toString()).replace(/(\\t|\\n)/g,'');
};
return {
compare: function(actual, expected) {
return {
pass: (preProcess(actual) === preProcess(expected)),
message: 'The functions were not the same'
};
}
};
}
}
Which is then used in my test as follows:
"use strict";
let someExternalFunction = require('../../lib/someExternalFunction');
let thingBeingTested = require('../../lib/thingBeingTested');
let customMatchers = require('../support/customMatchers');
describe('myTests', function() {
beforeEach(function() {
jasmine.addMatchers(customMatchers);
let app = {
use: function() {}
};
spyOn(app, 'use');
thingBeingTested(app);
});
it('calls app.use with the correct function', function() {
expect(app.use.calls.count()).toBe(1);
expect(app.use.calls.argsFor(0)).toBeTheSameFunctionAs(someExternalFunction);
});
});
If you want to compare two objects but ignore their functions, you can use the methods _.isEqualWith together with _.isFunction from lodash as follows.
function ignoreFunctions(objValue, otherValue) {
if (_.isFunction(objValue) && _.isFunction(otherValue)) {
return true;
}
}
it('check object equality but ignore their functions', () => {
...
expect(_.isEqualWith(actualObject, expectedObject, ignoreFunctions)).toBeTrue();
});

Using Backbone-relational with CoffeeScript

I'm trying to use a Backbone-relational and CoffeeScript in a project.The following is an example in CoffeeScript of the type of things I'm trying to model :
class NestedModel extends Backbone.RelationalModel
defaults:
Description: 'A nested model'
NestedModel.setup()
class MainModel extends Backbone.RelationalModel
defaults:
Description: 'A MainModel description'
StartDate: null
relations: [
type: Backbone.HasOne
key: 'nestedmodel'
relatedModel: 'NestedModel'
includeInJSON: '_id'
reverseRelation:
type: Backbone.HasOne
includeInJSON: '_id'
key: 'mainmodel'
]
MainModel.setup()
nm = new NestedModel()
mm = new MainModel(nestedmodel: nm)
console.log mm.get("nestedmodel").get("mainmodel").get("Description")
return
That CoffeeScript produces the following JavaScript:
var MainModel, NestedModel, mm, nm;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
NestedModel = (function() {
__extends(NestedModel, Backbone.RelationalModel);
function NestedModel() {
NestedModel.__super__.constructor.apply(this, arguments);
}
NestedModel.prototype.defaults = {
Description: 'A nested model'
};
return NestedModel;
})();
NestedModel.setup();
MainModel = (function() {
__extends(MainModel, Backbone.RelationalModel);
function MainModel() {
MainModel.__super__.constructor.apply(this, arguments);
}
MainModel.prototype.defaults = {
Description: 'A MainModel description',
StartDate: null
};
MainModel.prototype.relations = [
{
type: Backbone.HasOne,
key: 'nestedmodel',
relatedModel: 'NestedModel',
includeInJSON: '_id',
reverseRelation: {
type: Backbone.HasOne,
includeInJSON: '_id',
key: 'mainmodel'
}
}
];
return MainModel;
})();
MainModel.setup();
nm = new NestedModel();
mm = new MainModel({
nestedmodel: nm
});
console.log(mm.get("nestedmodel").get("mainmodel").get("Description"));
return;
Which produces the following warning and error
Warning:
Relation= child
; no model, key or relatedModel (function MainModel() {
MainModel.__super__.constructor.apply(this, arguments);
}, "nestedmodel", undefined)
Error:
Uncaught TypeError: Cannot call method 'get' of undefined
Simply removing the 'NestedModel' variable from the 1st line of generated JavaScript
var MainModel, NestedModel, mm, nm;
Causes the correct behaviour. Obviously I can't keep removing the variable definition from the generated JavaScript. What am I doing wrong?
Ok, it appears to be a scoping issue. See the following jsFiddle example. But why can't I just refer to the classes in the local function scope?
But why can't I just refer to the classes in the local function scope?
Classes are implemented as Immediately Invoked Function Expressions
The key to understanding design patterns such as immediately-invoked function expressions is to realize JavaScript has function scope (but not block scope) and passes values by reference inside a closure.
References
Immediately Invoked Function Expressions

Resources