Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-3341

Custom fields (demongoize) behavior unintuitive

    • Type: Icon: Task Task
    • Resolution: Done
    • 4.0.0 final
    • Affects Version/s: None
    • Component/s: None
    • None

      Current behavior: initialize a new object on read

      Right now, specifying a custom field type with

      Unable to find source-code formatter for language: type. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      : MyType

      calls the

      Unable to find source-code formatter for language: demongoize. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      
      

      every time the attribute is read, which initializes a new object for the field. So you get unexpected behavior:

      class Post
      field :author, type: Author
      end

      post = Post.first
      post.author.name = "new name"
      post.author.name # < — changes would be lost because the second call to 'post.author' instantiates a new object!

      I don't think I'm the only one who found this surprising: see https://github.com/mongoid/mongoid/issues/1604#issuecomment-3547128
      and https://github.com/mongoid/mongoid/issues/2951.

      Current work around (inconvenient)

      There's a solution, which is to assign the field object on the first time and then manipulate that local variable:

      post = Post.first
      author = post.author
      author.name = "new name"
      post.save

      But this is fairly inconvenient, and if you forget to do so, you can find yourself wondering why changes aren't saved.

      Proposed work-around

      I hacked together a solution that basically memoizes the object returned from demongoize, and the getter and setter created by field would first look to see if an object is already in memory.

      This works alright, but I wanted to see if there's work being done on this, or if there's a better way to handle things I'm completely missing. I'd be happy to take a stab at putting together a more robust solution.

            Assignee:
            Unassigned Unassigned
            Reporter:
            sherwinyu sherwinyu
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: