Migrating an Activerecord database to Mongoid - ruby-on-rails

I'm new to Rails programming. I was thinking about implementing devise and omniauth authentication per railscast tutorial. Since I don't know mongoid yet, I was planning on just starting with Activerecord. Eventually I want to use Mongoid I think.
How would I do a migration from Activerecord to Mongoid?
I just want to get rolling with my project. Especially when I have few users Activerecord will probably be sufficient. I've never done this before, so hopefully someone can tell me if this approach is going to be way more trouble than it's worth. Does it make more sense for me to take more time now to learn mongoid now instead?
I'm looking forward to hearing from you Rails veterans.

You build your models, controllers and views exactly the using mongoid as you do using ActiveRecord, so there's little difference there. The big difference is in the way your data is actually stored and retrieved, which affects your models, which directly impacts your code.
A schema-less database like mongoDB can't protect you like MySQL can, and there is no simple way to do migrations using Mongoid.
If you're starting out, you should probably go with ActiveRecord just because the a lot of the information out there relies on you using ActiveRecord with a relational database.
However, a switch to mongo/mongoid is definitely worth any perceived pain, but unless you've used a relational database and ActiveRecord, you may not appreciate just how awesome mongo/mongoid can be!

I believe ActiveRecord is sufficient. And please think about those small gems/plugins which are handy but not able to work with Mongoid. Tutorials, screencasts - vast majority of them are based on default ORM/Mysql.
For now it's just not worth to spent time on Mongoid I think.

...and there is no simple way to do migrations using Mongoid.
This isn't true. It is actually quite simple to create migrations in Mongoid. If you want to add a column to a database table, simply add it as a "field" to the top of the Model class like so:
class User
include Mongoid::Document
field :email, type: String
field :phone, type: String
field :reputation, type: Integer
end
No creating migrations, no raking the database. Just add/remove fields as needed, restart the server, and you're good to go. You should however be wary of removing fields as they can break your code where you referenced them.

Related

Does using migrations with Rails/Mongoid/MongoDB make sense?

Should I create AR migrations as I'm changing my models? I am using Mongoid and MongoDB so I do not see any benefits. The only benefit that I can think of is renaming a field - but that I can also do with small script. Would that even work? My gut is telling me that I do not need migrations, but I'd like to hear from someone with more experience.
What is the best practice? Should I use migrations with MongoDB?
Since MongoDB does not (as at 2.6) provide any server-side schema enforcement, data migration scripts are not strictly required. This can be particularly helpful for speed of development.
However, it may still make sense for you to create migrations for your production data if you want to practice good "data hygiene" and ensure consistency across different deployments.
For example:
removing unused fields
adding new required fields
setting default values
renaming fields
loading required data/fixtures
ensuring required indexes
You certainly have the choice of doing any of the above as one-off scripts or handling exception cases in your application code. For example, you can lazily add missing fields or defaults as documents are loaded from the database for editing.
For Mongoid in particular you may want to try the mongoid_rails_migrations gem.
Mongo DB documents are schema-less therefore migrations are not needed. You can just define fields in your mongoid models like:
field :name, type: String
Check the mongoid documentation for supported fields.

Can we mix Mongodb dynamic attributes to an ActiveRecord model?

We are using a dynamic attributes plugin similar to this:
http://codaset.com/joelmoss/dynamic-attributes
Which allows us to store dynamic attributes in our rails model. Those dynamic attributes are in a single database column. We are facing performance issues because of this and I am wondering if MongoId, MongoMapper or other rails plugins will allow us to keep some attribute in ActiveRecord (keeping the < ActiveRecord::Base) but store the dynamic attributes in mongodb. We want to do this because we need to keep using MySQL for most of our existing system, but use MongoDB to store dynamic attributes about some models.
Basically this is what I am talking about:
http://www.railsinside.com/plugins/242-quickly-add-couchdb-to-existing-rails-models-with-stuffing.html
This plugin does the exact same thing using CouchDB.
I don't see any reason that MongoDB can't handle the same thing.
MongoMapper should implement the ActiveRecord pattern. However, Mongo also has some simple drivers for Ruby. All in all, the concept of storing dynamic attributes is a perfect use-case for MongoDB.
If you don't mind skipping "ActiveRecord" you can probably cook up your own using the basic Mongo drivers with very little work.
If you can't figure out the steps to do this, I would suggest pinging the groups (http://groups.google.com/mongodb-user/) and asking Kyle Banker directly (he's their ruby expert).

Models in Rails are implicit, is this an annoying thing?

Considering models in Rails:
class Organization < ActiveRecord::Base
belongs_to :OrgType
end
Does it bother you that models in Rails don't include the fields that made the entity?
I know this is done for DRY's sake but you have to check the data base tables schema every time you want to check model's fields.
If you prefer a declarative style of ORM model, you might want to check out DataMapper or Sequel, both of which are easy to plug in to Rails 3.
Not annoying for me... ever since I started using the annotate-models gem to automatically add comments to the top of my model files, listing the fields associated with that model.
I was listening to a podcast a few months ago where the guy hosting the cast and the guest were advocating that Rails should take this path, and do away with migrations. The guy kept repeating "migrations must die", suggesting there be a way to specify your schema on the model instead.
I cannot disagree more, and I hope Rails never takes this path. Not only is it not DRY, but I like the fact that Rails encourages you to be aware of your own databases schema and structure.
In addition, there would be no way to keep a history of your schema if models were what controlled it, without having them be extremely cluttered. Migrations are essentially version control for your database that evolves with your application...and I wouldn't want to not have that.
Let's assume that OrgType has a field called position. This is common when you want to present a select list to the users who will be choosing a type. It's highly unlikely that your Organization will ever care about this field. Now extrapolate this to other related models with fields that other models don't care about, and add in the fact that if you ever wanted to change one of these fields you'd then have to hunt down each declaration of them, not just each place where they are used.
It's a mess.
Open up your db tool and look at your fields when you want to know what they are. Keep your models clean and readable. If you see code like this:
organization.org_type.name
It's pretty obvious that OrgType has a name field, without having to look it up, and without having to wade through configuration clutter in each model.

How to mix mongodb and a traditional db in Rails?

I am considering using MongoDB (mongo-mapper) for a portion of my rails application. I am not ready to go whole hog MongoDB because there are too many useful gems that depend on a traditional DB.
That being said there are parts of my application that would be great to leverage a document database.
Has anyone had success mixing the two approaches? How do you link activerecord models with mongomapper models?
MongoMapper doesn't implement ActiveModel yet, but I think there are a few forks on github that do. You could use Mongoid instead (which does) and your relationships between Mongoid docs and ActiveRecord entries would just magically work. I know a number of people are doing that.
That said, I wouldn't want to mix them unless I absolutely had to have an RDBMS for some reason.
Here a presentation about this issue: http://nosql.mypopescu.com/post/541657350/presentation-blending-nosql-and-sql-at-confoo
I don't know ROR so I can't judge it is a good presentation.
http://railscasts.com/episodes/194-mongodb-and-mongomapper
http://www.mongodb.org/display/DOCS/Object+Mappers+for+Ruby+and+MongoDB
http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails
http://www.mongodb.org/display/DOCS/Ruby+Language+Center
You need to mixin mongomapper with the model class
This gives you freedom to define the key-value pairs other than activerecord
include MongoMapper::Document
Dead simple I think.

How to create a user customizable database (like Zoho creator) in Rails?

I'm learning Rails, and the target of my experiments is to realize something similar to Zoho Creator, Flexlist or Mytaskhelper, i.e. an app where the user can create his own database schema and views. What's the best strategy to pursue this?
I saw something about the Entity-Attribute-Value (EAV) but I'm not sure whether it's the best strategy or if there is some support in Rails for it.
If there was any tutorial in Rails about a similar project it would be great.
Probably it's not the easiest star for learning a new language and framework, but it would be something I really plan to do since a long time.
Your best bet will be MongoDB. It is easy to learn (because the query language is JavaScript) and it provides a schema-less data store. I would create a document for each form that defines the structure of the form. Then, whenever a user submits the data, you can put the data into a generic structure and store it in a collection based on the name of the form. In MongoDB collections are like tables, but you can create them on the fly. You can also create indexes on the fly to speed searches.
The problem you are trying to solve is one of the primary use cases for document oriented databases which MongoDB is. There are several other document oriented databases out there, but in my opinion MongoDB has the best API at the moment.
Give the MongoDB Ruby tutorial a read and I am sure you will want to give it a try.
Do NOT use a relational database to do this. Creating tables on the fly will be miserable and is a security hazard, not just for your system, but for the data of your users as well. You can avoid creating tables on the fly by creating a complex schema that tracks the form structures and each field type would require its own table. Rails makes this less painful with polymorphic associations, but it definitely is not pretty.
I think it's not exactly what you want, but this http://github.com/LeonB/has_magic_columns_fork but apparently this does something similar and you may get some idea to get started.
Using a document store like mongodb or couchdb would be the best way forward, as they are schema-less.
It should be possible to generate database tables by sending DDL-statements directly to the server or by dynamical generating a migration. Then you can generate the corresponding ActiveRecord models using Class.new(ActiveRecord::Base) do ... end. In principle this should work, but it has to be done with some care. But this definitely no job for a beginner.
A second solution could be to use MongoMapper and MongoDB. My idea is to use a collection to store the rows of your table and since MongoDB is schema less you can simply add attributes.
Using EntryAttributeValue allows you to store any schema data in a set amount of tables, however the performance implications and maintenance issues this creates may very well not be worth it.
Alternately you could store your data in XML and generate an XML schema to validate against.
All "generic" solutions will have issues with foreign keys or other constraints, uless you do all of that validation in memory before storage.

Resources