Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

ActiveSupport #to_json doesn't work with DM

#4547

object#to_json will fail with "ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself"
This is due to the usage of "instance_values" in the #as_json method. DM objects carry a _@repository ivar which carries a reference to the original object.

This can be fixed by adding "dm-serializer" to the Gemfile, which implements its own #to_json method.

on line 137 of activesupport/lib/active_support/json/encoding

  def as_json(options = nil)

if respond_to?(:to_hash)
  to_hash
else
  instance_values
end



end

The following will reproduce the issue

require 'dm-core'
require 'active_support'
require 'active_support/json'
class Foo
  include DataMapper::Resource
  property :id, Serial
  property :name, String
end
DataMapper.setup(:default, 'sqlite3::memory:')
DataMapper.auto_migrate!
Foo.create(:name => "foo").to_json

Reported by siplux · May 6th, 2010 @ 10:55 PM

State: invalid
Milestone: none
Assigned to: José Valim José Valim
Importance: Low

Activity

  1. siplux
    siplux
    • Tag changed from rails3 compatibility, datamapper, rails3 to rails3 compatibility, activesupport, datamapper, rails3

    May 8th, 2010 @ 11:46 PM

  2. Dan Pickett
    Dan Pickett
    • Tag changed from rails3 compatibility, activesupport, datamapper, rails3 to rails3 compatibility, activesupport, bugmash, datamapper, rails3

    May 9th, 2010 @ 06:36 PM

  3. Lawrence Pit
    Lawrence Pit

    I also have this with ActiveRecord

    May 11th, 2010 @ 12:09 PM

  4. Neeraj Singh
    Neeraj Singh

    @lawrence Can you provide an example where you are running into same problem with ActiveRecord.

    I am able to reproduce this error with DM.

    I guess if one of the instance variables refers back to the original object as is the case with the first example provided then I see two choices.

    1) Let use pass an option :ignore_circular_reference => true. In this case in stead of raising an error, to_json method will ignore the circular reference and will move on.

    2) Let user pass an option :ignore_items => _my_intance_variable. This will provide more control to user and rather than ignoring all circular references, user is asking to_json to ignore just this variable.

    May 11th, 2010 @ 02:44 PM

  5. blackgold9
    blackgold9

    I hit the same thing with my models.
    In my case, it fails if i attempt to call to_json on an activerelation object (i.e. church.where().to_json), but works if i do church.where().to_a.to_json

    my model is:

    class Church < ActiveRecord::Base
    has_many :people has_many :groups validates_presence_of :name end

    The only property it has is name.

    May 12th, 2010 @ 06:03 AM

  6. Santiago Pastorino
    Santiago Pastorino

    Can someone provide a failing test using ActiveRecord? i've tried the thing that blackgold9 said but works for me ...
    http://pastie.org/957044

    May 12th, 2010 @ 03:25 PM

  7. Ryan Bigg
    Ryan Bigg
    • State changed from new to incomplete

    Please provide a test case and patch for this issue.

    May 13th, 2010 @ 11:56 PM

  8. Bernerd Schaefer
    Bernerd Schaefer

    The issue here is that ActiveSupport defines Object#to_json, and therefore Post.where.to_json tries to dump the ActiveRecord::Relation object instead of passing the method call on to it's internal collection. Note, this also applies to Object#to_yaml:

    # script/rails console
    include Test::Unit::Assertions
    
    relation = Post.where # or Post.where(:author_id => 1), etc.
    
    assert_nothing_raised(ActiveSupport::JSON::Encoding::CircularReferenceError) { relation.to_json } # fails
    assert_nothing_raised(TypeError) { relation.to_yaml } # fails
    
    ActiveRecord::Relation.send(:undef_method, :to_json)
    ActiveRecord::Relation.send(:undef_method, :to_yaml)
    
    assert_equal relation.to_a.to_json, relation.to_json # and now passes
    assert_equal relation.to_a.to_yaml, relation.to_yaml # and now passes
    

    This is important because it causes the following code to generate a 500 when requesting /posts/mine.json:

    class PostsController < ApplicationController
      respond_to :html, :xml, :json
      def mine
        @posts = Posts.where(:author_id => 1)
        respond_with(@clients)
      end
    end
    

    May 25th, 2010 @ 12:35 AM

  9. Marcin Kulik
    Marcin Kulik

    Requiring "json/pure" solves the problem for DataMapper, you just need to implement to_json for your models (or for DataMapper::Model).

    June 10th, 2010 @ 10:53 AM

  10. Lawrence Pit
    Lawrence Pit

    What Bernerd says.. exactly the issue I have. None of my controllers work when a json request is done. You'd think this workaround would work:

       def mine
         @posts = Posts.where(:author_id => 1).all
         respond_with(@posts)
       end
    

    But that too fails in rails edge since a while, with "ArgumentError: wrong number of arguments (2 for 1)". Posts.where(:author_id => 1).to_yaml does work, Posts.where(:author_id => 1).to_json doesn't. I attempted to create a patch, but for some reason the delegation of to_json to to_a in ActiveRecord::Relation doesn't work. Anybody else have an idea?

    (see attached what I tried; I also tried what Bernerd did, undef_method of to_json, same result)

    June 10th, 2010 @ 12:28 PM

  11. Neeraj Singh
    Neeraj Singh
    • Tag changed from rails3 compatibility, activesupport, bugmash, datamapper, rails3 to rails3 compatibility, activesupport, bugmash, datamapper, patch, rails3

    Attached is a patch along with test which makes it possible to have code like

    User.where(:name => 'John').to_json
    

    June 10th, 2010 @ 04:07 PM

  12. José Valim
    José Valim

    I'm not sure if we should allow Post.where(:omg).to_json. If so, what about to_xml? And to_yaml?

    June 10th, 2010 @ 06:59 PM

  13. Ola Tuvesson
    Ola Tuvesson
    • Tag changed from rails3 compatibility, activesupport, bugmash, datamapper, patch, rails3 to json to_json, rails3 compatibility, activesupport, bugmash, datamapper, patch, rails3

    I am having this same issue with a named scope.

    Given this model:

    class Listing < ActiveRecord::Base
      belongs_to :company
      scope :approved, lambda {
        where("approved = ?", true)
      }
    end
    

    And this controller:

    def index
      @listings = Listing.all
      @approved = Listing.approved
      ...
    end
    

    This works:

    respond_to do |format|
      format.json { render :json => @listings }
    end
    

    Whereas using the named scope fails with a CircularReferenceError:

    respond_to do |format|
      format.json { render :json => @approved }
    end
    

    Note: this is in Rails3b3

    June 22nd, 2010 @ 02:20 AM

  14. Dan Sully
    Dan Sully

    This is still an issue with DataMapper 1.0.0 and Rails3 beta4. The above work-arounds using json/pure or dm-serializers don't work for me.

    The test script by the original poster still fails.

    June 22nd, 2010 @ 11:22 PM

  15. Neeraj Singh
    Neeraj Singh
    • Assigned user set to José Valim

    Attached is patch with test.

    June 23rd, 2010 @ 03:09 PM

  16. Neeraj Singh
    Neeraj Singh

    Attached is patch with to_xml support. This patch needs be applied in addition to the patch previously mentioned.

    June 23rd, 2010 @ 04:56 PM

  17. Repository
    Repository
    • State changed from incomplete to resolved

    (from [eb04408a20628a49296e0859425940b39a83ec63]) ActiveRecord's relation object should respond to to_json and to_yaml

    [#4547 ActiveSupport #to_json doesn't work with DM state:resolved]

    Signed-off-by: José Valim jose.valim@gmail.com
    http://github.com/rails/rails/commit/eb04408a20628a49296e0859425940...

    June 23rd, 2010 @ 05:17 PM

  18. Marcin Kulik
    Marcin Kulik

    How above ActiveRecord patch is supposed to solve serializing DataMapper objects??

    June 23rd, 2010 @ 07:20 PM

  19. José Valim
    José Valim
    • State changed from resolved to open

    Hahahaha! The patch was not supposed to close this issue, it just solves another issue raise in this same thread. Reopening.

    June 23rd, 2010 @ 07:25 PM

  20. José Valim
    José Valim
    • State changed from open to invalid
    • Importance changed from to Low

    About Datamapper: you need to define a as_json implementation for your models, otherwise Rails will use the default implementation causing the errors you mentioned. Maybe, dm-rails guys, could include a default as_json implementation. But I cannot see anything Rails could do here.

    June 26th, 2010 @ 10:49 AM