Mongoid: embedded one to one, with pure json input
I'm trying embedded one to one mongoid model where the "embedded child" is a pure json input coming from an external API.
The parent document is defined like follow:
./app/models/user.rb
class User
include Mongoid::Document
field :nickname, :type => String
embeds_one :watchlist
def self.create_with_omniauth(auth)
create! do |user|
user.nickname = auth['user_info']['nickname']
end
end
end
the child is defined like follow (using a mix of "mongo ruby driver" & "mongoid ORM"):
./app/models/watchlist.rb
require 'mongo'
class Watchlist
include Mongoid::Document
embedded_in :user
def self.watched(nickname)
conn = FaradayStack.build 'https://api.github.com'
#resp = conn.get '/users/:nickname/watched'
resp = conn.get '/users/lgs/watched'
db = Mongo::Connection.new.db('gitwatch_dev')
coll = db.collection('watchlist')
coll.insert(resp.body)
end
end
The controllers look like this:
app/controllers/home_controller.rb
class HomeController < ApplicationController
def index
if current_user
nickname = request.env["omniauth.auth"]
@watched = Watchlist.watched(nickname)
end
end
end
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
#user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
user = User.where(:provider => auth['provider'], :uid => auth['uid']).first || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
...
end
Now, what I get is a gitwatch_dev mongodb, with two UNRELATED "mongo models", in mongo cli they look like the follow:
> db.users.find()
{ "_id" : ObjectId("4e117b951d41c80b14000001"), "provider" : "github", "uid" : "1573", "name" : "Luca G. Soave", "email" : "luca.soave@gmail.com", "nickname" : "lgs", "token" : "a512434559b07feb0a98d199238764sde9876", "secret" : null, "user_hash" : "{\"plan\"=>{\"name\"=>\"free\", \"collaborators\"=>0, \"space\"=>307200, \"private_repos\"=>0}, \"gravatar_id\"=>\"9c7d80ebc20ab8xx994e57519ae\", \"company\"=>\"http://www.linkedin.com/in/lucasoave\", \"name\"=>\"Luca G. Soave\", \"created_at\"=>\"2008/02/28 05:26:40 -0800\", \"location\"=>\"Milan - Italy\", \"disk_usage\"=>113860, \"collaborators\"=>0, \"public_repo_count\"=>32, \"public_gist_count\"=>85, \"blog\"=>nil, \"following_count\"=>140, \"id\"=>1573, \"owned_private_repo_count\"=>0, \"private_gist_count\"=>2, \"type\"=>\"User\", \"permission\"=>nil, \"total_private_repo_count\"=>0, \"followers_count\"=>9, \"login\"=>\"lgs\", \"email\"=>\"luca.soave@gmail.com\"}" }
> db.watchlist.find()
{ "_id" : ObjectId("4e117bd31d41c80b14000002"), "open_issues" : 47, "url" : "https://api.github.com/repos/mojombo/grit", "watchers" : 997, "homepage" : "ht开发者_C百科tp://grit.rubyforge.org/", "master_branch" : null, "language" : "Ruby", "fork" : false, "pushed_at" : "Sat Jul 02 2011 01:02:45 GMT+0200 (CEST)", "created_at" : "Mon Oct 29 2007 15:37:16 GMT+0100 (CET)", "git_url" : "git://github.com/mojombo/grit.git", "html_url" : "https://github.com/mojombo/grit", "private" : false, "size" : 2482, "owner" : { "url" : "https://api.github.com/users/mojombo", "login" : "mojombo", "avatar_url" : "https://secure.gravatar.com/avatar/25c7c18223fb42a4c6ae1c8db6f50f9b?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png", "id" : 1 }, "description" : "Grit gives you object oriented read/write access to Git repositories via Ruby.", "name" : "grit", "svn_url" : "https://svn.github.com/mojombo/grit", "ssh_url" : "git@github.com:mojombo/grit.git", "clone_url" : "https://github.com/mojombo/grit.git", "forks" : 140 }
...
...
while I'd like to get a nested "child into parend" json, something like the embedded one to one mongoid model example:
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"name" : {
"_id" : ObjectId("4d3ed089fb60ab534684b7e0"),
"vorname" : "Heinrich",
"nachname" : "Heine"
}
}
Than, I'm also looking for doing that in "pure mongoid" without mess of ruby drivers, but cannot find out the way ...
UPDATE jul 6 2011 - thanks to Rubish Gupta:
it finally works with
user.create_watchlist['dynamic_attribute'] = resp.body
in the User parent model: app/models/user.rb see the full code at http://www.pastie.org/2169671
The problem here is with these lines:
db = Mongo::Connection.new.db('gitwatch_dev')
coll = db.collection('watchlist')
coll.insert(resp.body)
Here what you are doing is accessing the collection watchlist, which you do not want to create and want to embed the records in users collection.
Correct way to do would be to make a function watch(repo)
like following in User
:
def watch(repo)
# obtain the resp
self.create_watchlist(resp.body)
end
But you should enable dynamic attributes in mongoid.yml to do this.
In you controller you should do current_user.watch(repo)
instead of the three lines noted above.
精彩评论