1

http://mongotips.com/b/array-keys-allow-for-modeling-simplicity/をフォローしようとしています

ストーリードキュメントと評価ドキュメントがあります。ユーザーがストーリーを評価するので、ユーザーによる評価と多くの関係を作成したいと思いました。

class StoryRating
  include MongoMapper::Document

  # key <name>, <type>
  key :user_id, ObjectId
  key :rating, Integer
  timestamps!

end

class Story
  include MongoMapper::Document

  # key <name>, <type>
  timestamps!
  key :title, String
  key :ratings, Array, :index => true

  many :story_ratings, :in => :ratings

end

それで

irb(main):006:0> s = Story.create  
irb(main):008:0> s.ratings.push(Rating.new(user_id: '0923ksjdfkjas'))  
irb(main):009:0> s.ratings.last.save  
=> true  
irb(main):010:0> s.save  
BSON::InvalidDocument: Cannot serialize an object of class StoryRating into BSON.  
    from /usr/local/lib/ruby/gems/1.9.1/gems/bson-1.6.2/lib/bson/bson_c.rb:24:in `serialize' (...)

なんで?

4

1 に答える 1

3

JohnNunemakerの「ArrayKeysAllowfor Modeling Simplicity」の説明に従って必要なものを取得するには、内部の「rating」Array.pushではなく、関連付け「story_rating」メソッドをプッシュ/追加に使用する必要があります。違いは、アソシエーションメソッドでは、MongoMapperがBSON :: ObjectId参照を配列に挿入し、後者ではRuby StoryRatingオブジェクトを配列にプッシュし、基盤となるドライバードライバーがそれをシリアル化できないことです。

これが私のために働くテストで、違いを示しています。これがお役に立てば幸いです。

テスト

require 'test_helper'

class Object
  def to_pretty_json
    JSON.pretty_generate(JSON.parse(self.to_json))
  end
end

class StoryTest < ActiveSupport::TestCase
  def setup
    User.delete_all
    Story.delete_all
    StoryRating.delete_all
    @stories_coll = Mongo::Connection.new['free11513_mongomapper_bson_test']['stories']
  end

  test "Array Keys" do
    user = User.create(:name => 'Gary')
    story = Story.create(:title => 'A Tale of Two Cities')
    rating = StoryRating.create(:user_id => user.id, :rating => 5)
    assert_equal(1, StoryRating.count)
    story.ratings.push(rating)
    p story.ratings
    assert_raise(BSON::InvalidDocument) { story.save }
    story.ratings.pop
    story.story_ratings.push(rating) # note story.story_ratings, NOT story.ratings
    p story.ratings
    assert_nothing_raised(BSON::InvalidDocument) { story.save }
    assert_equal(1, Story.count)
    puts Story.all(:ratings => rating.id).to_pretty_json
  end
end

結果

Run options: --name=test_Array_Keys

# Running tests:

[#<StoryRating _id: BSON::ObjectId('4fa98c25e4d30b9765000003'), created_at: Tue, 08 May 2012 21:12:05 UTC +00:00, rating: 5, updated_at: Tue, 08 May 2012 21:12:05 UTC +00:00, user_id: BSON::ObjectId('4fa98c25e4d30b9765000001')>]
[BSON::ObjectId('4fa98c25e4d30b9765000003')]
[
  {
    "created_at": "2012-05-08T21:12:05Z",
    "id": "4fa98c25e4d30b9765000002",
    "ratings": [
      "4fa98c25e4d30b9765000003"
    ],
    "title": "A Tale of Two Cities",
    "updated_at": "2012-05-08T21:12:05Z"
  }
]
.

Finished tests in 0.023377s, 42.7771 tests/s, 171.1084 assertions/s.

1 tests, 4 assertions, 0 failures, 0 errors, 0 skips
于 2012-05-08T19:08:18.667 に答える