ruby-on-railscoffeescriptbatman.js

Batman.js model encoding issue


I'm running into an interesting issue with a complex model association.

I have a Project, which has many Tasks, as well as a sole Task that it derives it's own information from. (Tasks can be converted to Projects to embed additional Tasks underneath them)

class Settr.Project extends Batman.Model
  @resourceName: 'projects'
  @storageKey: 'projects'

  @persist Batman.RailsStorage, serializeAsForm: false

  @belongsTo 'owner', name: 'User', inverseOf: 'projects'
  @belongsTo 'task',  inverseOf: 'project'
  @hasMany 'tasks'


  @encode 'task_id', 'owner_id'
  @encodeTimestamps()

The task Model may belong to a project's hasMany relationship, or it may play a hasOne relationship if it is the inverse of the 'task' property.

class Settr.Task extends Batman.Model
  @resourceName: 'tasks'
  @storageKey: 'tasks'

  @persist Batman.RailsStorage, serializeAsForm: false

  @belongsTo 'user'
  @belongsTo 'project', inverseOf: 'task', saveInLine: true
  @hasOne 'project'
  @hasMany 'entries', name: 'TaskEntry', inverseOf: 'task', saveInline: true

  @accessor 'lastEntry', ->
    @get('entries').reduce (a, b) ->
      (if a.created_at < b.created_at then a else b)

  @encode 'user_id', 'project_id'
  @encodeTimestamps()

In the future I will me implementing the ability to have Tasks repeat and allow for a history of a given's Tasks occurances to be viewed. This model is represented by TaskEntry

class Settr.TaskEntry extends Batman.Model
  @resourceName: 'entries'
  @storageKey: 'entries'

  @persist Batman.RailsStorage

  @PRIVACY_OPTIONS = ['is_public', 'is_private', 'is_follower']
  @DIFFICULTY_OPTIONS = ['','easy', 'moderate', 'hard']
  @STATUS_OPTIONS = ['incomplete', 'complete']

  @belongsTo 'task', inverseOf: 'entries'
  @urlNestsUnder 'task'

Now the issue. When I want to post a new Project, I have to embed a new Task for the Project, and give that Task a TaskEntry and set its title property. (Title is the only required field)

What is interesting is when my project is formatted like this: (same as above)

class Settr.Project extends Batman.Model
  @resourceName: 'projects'
  @storageKey: 'projects'

  @persist Batman.RailsStorage, serializeAsForm: false

  @belongsTo 'owner', name: 'User', inverseOf: 'projects'
  @belongsTo 'task',  inverseOf: 'project'
  @hasMany 'tasks'

  @encode 'task_id', 'owner_id'
  @encodeTimestamps()

I am able to retrieve Projects, but not post a new project.

If I encode the 'task' in the Project model, I am then able to post successfully, but am no longer able to retrieve. Example below.

class Settr.Project extends Batman.Model
  @resourceName: 'projects'
  @storageKey: 'projects'

  @persist Batman.RailsStorage, serializeAsForm: false

  @belongsTo 'owner', name: 'User', inverseOf: 'projects'
  @belongsTo 'task',  inverseOf: 'project'
  @hasMany 'tasks'

  @encode 'task_id', 'owner_id', 'task'
  @encodeTimestamps()

From the Batman.js API Docs on @encode, I have found that @encode can be customized like so.

@encode 'myProperty',
  decode: (value, key, incomingJSON, outgoingObject, record) -> # returns a value to set on the record
  encode: (value, key, builtJSON, record) ->                    # returns a value to put into the JSON
  as: "my_property"                                             # overrides "myProperty" as the JSON key

But I'm not quite sure if this is the right solution for me, or if my issue is somewhere else. If this is the solution I want, how do I use it appropriately? The documentation is a little bit over my head.

Thanks!


Solution

  • It might be caused by this naming conflict:

    @belongsTo 'project', inverseOf: 'task', saveInLine: true
    @hasOne 'project'
    

    That defines two accessors for project -- I think the later one overrides the earlier one.

    You could rename the hasOne association without changing the JSON API:

    @hasOne 'special_project', foreignKey: 'project_id'
    

    (you must provide foreignKey, otherwise it would default to special_project_id)