Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating Devise with Mongoid

I am developing a Ruby on Rails 3 application and this is the first time I use MongoDB.

I have been thinking for couple of days on this problem, and I don't find a good solution. There are two problems I want to discuss.

  1. The model
  2. How to integrate this with Devise

The application is a School Courses manager. It manages many schools, which contains many students, courses, professors and tasks.

The structure of one school – there a many– is:

  • School

    • Director
    • Students
    • Professors
    • Courses
    • Tasks
  • The Director is the admin of the school. He is the only one who can create professors, students and courses.

  • There is exactly 1 Director.
  • There can be (0 – many) courses.
  • There can be (0 – many) students
  • There can be (0 – many) professors
  • Students may be in (0 – many) courses.
  • Professors may be in (0 – many) courses.
  • For every course, there can be (0–many) tasks associated with (0 – many) students. Yes, professor can send specific tasks to specific students.

I though for a couple of days on how to architecture this collection of models on MongoDB using Mongoid, and I reach a possible solution. Yet I come from a Relational Database world and maybe this is an awful solution and I am abusing of 'embed' :)

  • Collection Schools
    • School 1
      • embed Director
      • embed Users
      • embed Courses
      • embed Tasks
    • School 2
      • embed Director
      • embed Users
      • embed Courses
      • embed Task

Models:

class User
   include Mongoid::Document

   field :first_name
   field :last_name
   field :email

   embedded_in :school, :inverse_of => :director
   embedded_in :school, :inverse_of => :students
   embedded_in :school, :inverse_of => :professors
end                                                 


class School
   include Mongoid::Document          

   field :name
   key :name 

   embeds_one :director, :class_name => "User"
   embeds_many :students, :class_name => "User"
   embeds_many :professors, :class_name => "User"

   validates :name, :presence => true  
end


class Task
   include Mongoid::Document

   field :name

   references_one :student, :class => "User"
   references_one :course
end

Also, I think I will use this class of wrap a collection a tasks. A professor creates a TaskCollection and assign students to it.

 class TaskCollection

     include Mongoid::Document

     field :name

     references_many :students, :stored_as => array, :class => "User"
     references_one :task

 end

So this is my first question. I need feedback. Is it the right way to use a document oriented database? Performance? Improvements? Errors?

And the second question. How can we integrate this in Devise?

My first try is this:

Routes.rb

devise_for :users, :path => 'schools/:school_id/users'

resources :schools do resources :documents, :only => [:index] resources :tasks, :only => [:index]
end

But when I do try do register and user I get an error.

http://localhost:3000/schools/pablo-de-olavide/users

 Mongoid::Errors::InvalidCollection in Devise/registrationsController#create

 Access to the collection for User is not allowed since it is an embedded document, please access a collection from the root document.

Thank you very much for your help.

like image 830
Nerian Avatar asked Dec 14 '10 18:12

Nerian


2 Answers

I just started playing with Devise and Mongoid myself.

Your immediate need is to make User a root document (i.e. not embedded) this is how Devise is expecting to interact with the User model. I don't know if it can be overridden easily to do what you want it to. Personally, I don't think it would make a lot of sense even if you could.

As to your document design question you should take a look at this from Mongdb http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Embedvs.Reference

From your example I would consider the User object to be a "First Class" object which would warrant its own collection.

like image 175
Michael Gattuso Avatar answered Sep 30 '22 21:09

Michael Gattuso


Here is the link from the Devise wiki with information about embedding users to another model:

How-To:-Embed-users-in-your-account-model-with-Mongoid

like image 41
Vassilis Avatar answered Sep 30 '22 20:09

Vassilis