Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial


Tyler Fowler
Tyler Fowler
20,743 Points

CoffeeScript preserve multiple `this` objects?

Foreward: I know this is more of a CoffeeScript question than JavaScript, but it applies equally to both as the => in CoffeeScript is just calling call or apply (can't remember which) at the end of the function and passing the this object. So not too different. Also I know it's somewhat of a complicated question but Stack Overflow is failing me at the moment.

From SO:

I'm in a rather unique situation (one I've never found myself in before) and I can't find anything on how it should be handled, so I thought I'd ask here. (and perhaps start a good discussion on how it should be handled)

I'm writing a Node.js/Express application that does a series of database calls in various route handlers. I'm using the node-sqlite3 module to make the database calls. In this case the user is uploading a file, so I take that from the form POST data and save it to the filesystem (will be moved to blob storage later) and generate some xml files for other reasons. The way that I name these files is by the id in the database to facilitate routes like '/file/:id' to GET the file later on, as well as leveraging the database to ensure I don't have name collision issues.

I'm doing this in CoffeeScript so I'm wrapping this model in a class, so it uses this (or @) to access these helper methods. Before I was doing a last_insert_rowid() call to get the id of the thing I just inserted but this opens me up to potential race conditions. So as it turns out when you do an INSERT in the node-sqlite3 module the callback it calls when it's done saves the last inserted row id in the this object (so (err) -> fileid = @.lastID). Now for some code (names changed and simplified).

uploadFile: (fileData, cb) ->
  @db.serialize =>
    # preserve the @ object to allow calls to class methods like @.saveFile
    @db.run 'insert into thing (val=$val)', $val: 'some_val', (err) ->
      if err
        cb err

      # @ refers to the this object provided by @db.run
      fileid = @.lastID

      async.waterfall [
        (async_cb) =>
          # uh oh, the @ object is the one from the db library, not my class
          # earning me a 'method undefined' error
          @.saveFile fileid, async_cb 
        # etc... you get the idea
      ], (err) -> cb err

So I'm needing to retain the class this object to access instance methods, but I also need to get the lastID value out of the this object returned by default from the callback in the db call. Obviously if I change the callback on the db call to fat arrows I can access my class methods, but then the @.lastID returns undefined.

What's the "proper" way to achieve this? (in CoffeeScript or JavaScript, doesn't particularly matter) I think that the way I can solve this is by assigning a context variable like ctxt = @ at the top of the method but obviously this isn't favorable. Any ideas?

EDIT: Oh, and I forgot to mention, I can't just name the file something else because I also need that id to update the database. The call to async.waterfall does: Save file -> generate xml metadata file & save it -> add the path of the xml file to the database entry retroactively. Though I could potentially use a statement to do that without completely isolated database calls, haven't investigated that yet.

EDIT #2: Adding a context does work. By this I mean putting ctxt = @ at the top of the method and where I use @db down in the call to async.waterfall replacing it with something like ctxt.run .... Not very elegant though.