Virtual Attributes in JugglingDB?

228 views
Skip to first unread message

Matt Hupman

unread,
Apr 5, 2013, 5:22:48 PM4/5/13
to compo...@googlegroups.com
Has anyone had any success creating a virtual attribute (attribute on model with all normal attribute properties except for persistence) in JugglingDB?  I'm trying to set up PassportJS and have created a User model.  My User model looks as follows:

User = describe 'User', ->
    property 'username', String
    property 'password_hash', String
    property 'password_salt', String
    set 'restPath', pathTo.users

Ideally, I would like to use a virtual properties for 'password' and 'password_confirmation'.  Then, implement a custom setter for password like so:

User.setter.password = (clearPass) ->
    @password_salt = @makeSalt()
    @password_hash = @encryptPassword(clearPass, @password_salt)

I could also use a custom validator to make sure that password == passwordConfirmation before proceeding with an update.  I was experimenting with Model.registerProperty() so that I could define a setter for the password field, but unfortunately Model.updateAttributes() updates only attributes that were passed in, instead of all that changed (via Model.propertyChanged(''))

Any suggestions?

Regards,
Matt

Andrew Krasnoff

unread,
Apr 6, 2013, 11:42:11 AM4/6/13
to compo...@googlegroups.com
Virtual attrs(via setter) is buggy in compound. So I suggest to use "beforeSave" callback for it. 
Like (coffeescript):

        # in controller
        user.password = body.password

        # in user model
        User.beforeSave = (next) ->
            if @password 
                pepper = app.get('pepper')
                salt = bcrypt.genSaltSync( app.get 'stretches' )
                @encrypted_password = bcrypt.hashSync(@password + pepper, salt)
            next()

P.S. mass-assignment doesn't work for attrs which is not defined in schema file


--
The official community of CompoundJS.
 
website: compoundjs.com
source: https://github.com/1602/compound
bug reports: https://github.com/1602/compound/issues?state=open
---
You received this message because you are subscribed to the Google Groups "CompoundJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compoundjs+...@googlegroups.com.
To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
С уважением,
Андрей Краснов

Alex Yaroshevich

unread,
Apr 7, 2013, 8:08:10 AM4/7/13
to compo...@googlegroups.com
What about creating virtual manually handled fields?
Each field of schema must be described as class (virtual or not), and must be stored to some specified storage (db, fs, remote service, ...) — that abstraction level can give us very flexible tool to make schemes incredibly powerful and still fast.
e.g., for files, EAV (values of), passwords (like in example here), auth hash from LDAP/twitter, et cetera.

Matt Hupman

unread,
Apr 8, 2013, 9:21:24 AM4/8/13
to compo...@googlegroups.com
Yes, but beforeSave isn't called in the case of updateAttributes, so I'd need to duplicate the code elsewhere.  It would be nice not to have to change controller code to accomodate a single attribute. I ran a quick test in Rails/ActiveRecord (which JugglingDB/CompoundJS seems to be closely modeling) and in AR, all attributes are updated, even ones affected by another attributes setter.  See the gist here: https://gist.github.com/mhupman/5336685

Would a good fix be to save the entire object inside updateAttributes instead of just the data that was passed in, like ActiveRecord?

Regards,
Matt

Andrew Krasnoff

unread,
Apr 8, 2013, 9:29:45 AM4/8/13
to compo...@googlegroups.com
I prefer do not use "updateAttributes" because there are no any mass-asignment protection in CompoundJS. So, I use "model.save()" instead

Matt Hupman

unread,
Apr 8, 2013, 9:36:31 AM4/8/13
to compo...@googlegroups.com
Good point, I didn't consider that.  Do you normally cherry pick each attribute you want to update in controller code then call .save() each time inside Controller.update()?

Anatoliy Chakkaev

unread,
Apr 8, 2013, 9:37:00 AM4/8/13
to compo...@googlegroups.com
Yes, but beforeSave isn't called in the case of updateAttributes
Not true. See http://jugglingdb.co/hooks.3.html#DESCRIPTION and check tests.

Matt Hupman

unread,
Apr 8, 2013, 9:44:55 AM4/8/13
to compo...@googlegroups.com, ma...@anatoliy.in
Yep, I just realized that.  Readme.md of JugglingDB is wrong though (see https://github.com/1602/jugglingdb/#object-lifecycle), that's what I was working off of - that will teach me to only trust the code :).  I'll send a PR to update the Readme.

Anatoliy Chakkaev

unread,
Apr 8, 2013, 9:50:22 AM4/8/13
to compo...@googlegroups.com
Thanks.


On Mon, Apr 8, 2013 at 5:44 PM, Matt Hupman <mhu...@citrrus.com> wrote:
Yep, I just realized that.  Readme.md of JugglingDB is wrong though (see https://github.com/1602/jugglingdb/#object-lifecycle), that's what I was working off of - that will teach me to only trust the code :).  I'll send a PR to update the Readme.

--

Andrew Krasnoff

unread,
Apr 8, 2013, 9:53:11 AM4/8/13
to compo...@googlegroups.com
Yes, I do somthing like:
    
    user.password = body.password
    user.save(err, callback)

Actually exists one more issue related with "virtual" attrs - we cannot define validation for such attrs in a model(just in a controller)


On Mon, Apr 8, 2013 at 8:36 PM, Matt Hupman <mhu...@citrrus.com> wrote:
Good point, I didn't consider that.  Do you normally cherry pick each attribute you want to update in controller code then call .save() each time inside Controller.update()?

--
The official community of CompoundJS.
 
website: compoundjs.com
source: https://github.com/1602/compound
bug reports: https://github.com/1602/compound/issues?state=open
---
You received this message because you are subscribed to the Google Groups "CompoundJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compoundjs+...@googlegroups.com.
To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Alex Yaroshevich

unread,
Apr 8, 2013, 9:58:14 AM4/8/13
to compo...@googlegroups.com
One more reason to move "virtuality" few layers above or in a new abstract layer who tells which fields should be stored in db and which doesn't.


On Monday, April 8, 2013 5:53:11 PM UTC+4, Andrew Krasnoff wrote:
Yes, I do somthing like:
    
    user.password = body.password
    user.save(err, callback)

Actually exists one more issue related with "virtual" attrs - we cannot define validation for such attrs in a model(just in a controller)

Andrew Krasnoff

unread,
Apr 8, 2013, 9:59:38 AM4/8/13
to compo...@googlegroups.com
schema file tells which fields should be stored in db and which doesn't.


--
The official community of CompoundJS.
 
website: compoundjs.com
source: https://github.com/1602/compound
bug reports: https://github.com/1602/compound/issues?state=open
---
You received this message because you are subscribed to the Google Groups "CompoundJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compoundjs+...@googlegroups.com.
To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Alex Yaroshevich

unread,
Apr 8, 2013, 10:04:07 AM4/8/13
to compo...@googlegroups.com
Actually, schema file don't know anything about virtual fields at the moment. So it can't tell us about which fields should not be stored. ;-)
But if schema files will have some additional functionality to determine data source for each field — it can take some decisions about which fields should be left untouched and that technique will get us a lot of possibilities described here.
8 О©╫О©╫О©╫О©╫О©╫О©╫ 2013 О©╫. 17:59
schema file tellsО©╫which fields should be stored in db and which doesn't.





--
О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫,
О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫
--
The official community of CompoundJS.
О©╫
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
О©╫
О©╫
8 О©╫О©╫О©╫О©╫О©╫О©╫ 2013 О©╫. 17:58
One more reason to move "virtuality" few layers above or in a new abstract layer who tells which fields should be stored in db and which doesn't.

On Monday, April 8, 2013 5:53:11 PM UTC+4, Andrew Krasnoff wrote: --
The official community of CompoundJS.
О©╫
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
О©╫
О©╫
8 О©╫О©╫О©╫О©╫О©╫О©╫ 2013 О©╫. 17:53
Yes, I do somthing like:
О©╫ О©╫О©╫
О©╫ О©╫ user.password = body.password
О©╫ О©╫ user.save(err, callback)

Actually exists one more issue related with "virtual" attrs - we cannot define validation for such attrs in a model(just in a controller)





--
О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫,
О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫
--
The official community of CompoundJS.
О©╫
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
О©╫
О©╫
8 О©╫О©╫О©╫О©╫О©╫О©╫ 2013 О©╫. 17:36
Good point, I didn't consider that. О©╫Do you normally cherry pick each attribute you want to update in controller code then call .save() each time inside Controller.update()? --
The official community of CompoundJS.
О©╫
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
О©╫
О©╫
8 О©╫О©╫О©╫О©╫О©╫О©╫ 2013 О©╫. 17:29
I prefer do not use "updateAttributes" because there are no any mass-asignment protection in CompoundJS. So, I use "model.save()" instead





--
О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫,
О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫
--
The official community of CompoundJS.
О©╫
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
О©╫
О©╫


Andrew Krasnoff

unread,
Apr 8, 2013, 10:08:08 AM4/8/13
to compo...@googlegroups.com
As I understand, right now, all fields which defined in schema file are stored in DB.
So just schema file defines which fields should be stored in DB. And it is enough.


On Mon, Apr 8, 2013 at 9:04 PM, Alex Yaroshevich <zxq...@gmail.com> wrote:
Actually, schema file don't know anything about virtual fields at the moment. So it can't tell us about which fields should not be stored. ;-)
But if schema files will have some additional functionality to determine data source for each field — it can take some decisions about which fields should be left untouched and that technique will get us a lot of possibilities described here.
8 апреля 2013 г. 17:59
schema file tells which fields should be stored in db and which doesn't.





--
С уважением,
Андрей Краснов
--
The official community of CompoundJS.
 
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
8 апреля 2013 г. 17:58
One more reason to move "virtuality" few layers above or in a new abstract layer who tells which fields should be stored in db and which doesn't.

On Monday, April 8, 2013 5:53:11 PM UTC+4, Andrew Krasnoff wrote: --
The official community of CompoundJS.
 
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
8 апреля 2013 г. 17:53
Yes, I do somthing like:
    
    user.password = body.password
    user.save(err, callback)

Actually exists one more issue related with "virtual" attrs - we cannot define validation for such attrs in a model(just in a controller)





--
С уважением,
Андрей Краснов
--
The official community of CompoundJS.
 
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
8 апреля 2013 г. 17:36
Good point, I didn't consider that.  Do you normally cherry pick each attribute you want to update in controller code then call .save() each time inside Controller.update()? --
The official community of CompoundJS.
 
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
8 апреля 2013 г. 17:29
I prefer do not use "updateAttributes" because there are no any mass-asignment protection in CompoundJS. So, I use "model.save()" instead





--
С уважением,
Андрей Краснов
--
The official community of CompoundJS.
 
You received this message because you are subscribed to a topic in the Google Groups "CompoundJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/compoundjs/aI3YplkREI0/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
The official community of CompoundJS.
 
You received this message because you are subscribed to the Google Groups "CompoundJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compoundjs+...@googlegroups.com.

To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
postbox-contact.jpg
postbox-contact.jpg
postbox-contact.jpg

Alex Yaroshevich

unread,
Apr 8, 2013, 10:10:25 AM4/8/13
to compo...@googlegroups.com
Sad, but okay! Thanks.

Matt Hupman

unread,
Apr 8, 2013, 12:00:45 PM4/8/13
to compo...@googlegroups.com
If anyone is curious, here is how I got it working:  https://gist.github.com/mhupman/5337835.  The trick is to use Model.registerProperty() to get the setter/getter functionality (ala attr_accessor in ActiveRecord) and use a Model.beforeSave() hook to ensure that the password_hash and password_salt fields are always updated.  This doesn't solve the problem that Andrew pointed out regarding mass-assignment, but my entire website requires authentication so I'm ok with that for now.  This method requires no changes to controller code, and both updates and saves work as expected.  Validations work as well!

Regards,
Matt

Andrew Krasnoff

unread,
Apr 8, 2013, 12:45:14 PM4/8/13
to compo...@googlegroups.com
Looks like a magic :))
Did you test validations for password fields ? for example password length ?


--
The official community of CompoundJS.
 
website: compoundjs.com
source: https://github.com/1602/compound
bug reports: https://github.com/1602/compound/issues?state=open
---
You received this message because you are subscribed to the Google Groups "CompoundJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to compoundjs+...@googlegroups.com.
To post to this group, send email to compo...@googlegroups.com.
Visit this group at http://groups.google.com/group/compoundjs?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Matt Hupman

unread,
Apr 8, 2013, 1:08:54 PM4/8/13
to compo...@googlegroups.com
Yep, validations work as well.  I've updated the original gist with a minimum length validation on password.

Matt Hupman

unread,
Apr 12, 2013, 2:49:47 PM4/12/13
to compo...@googlegroups.com
Unfortunately my technique no longer works in 0.2.0-30 due to the DataType sniffing added in Schema.registerProperty() (https://github.com/1602/jugglingdb/commit/41d34eb243a813dcd894a8fef21c8878ac53dd06#L2R232), but it works in 0.2.0-29, so I'll stay on that for now.  I've updated the Gist with the final solution for implementing a virtual attribute.  Hope this helps someone else out!

Andrew Krasnoff

unread,
Apr 12, 2013, 2:58:00 PM4/12/13
to compo...@googlegroups.com
jugglingdb 0.2.0-30 is not working for me at all since a lot of issues with relations - see https://github.com/1602/jugglingdb/issues/264
Reply all
Reply to author
Forward
0 new messages