Runtime changing model with mongodb/mongoid
In general it should be possible to update old documents with the new fields at runtime. There is no need for migrations in MongoDB.
You maybe want to write rake tasks to update your old documents with the new fields and default values.
You could find out these documents by checking those new fields which have per default a nil value.
Update
Easy style:
If you define a new field with a default value, this value should always be used as long as you set a new one:
app/models/my_model.rb
class MyModel
include Mongoid::Document
field :name, type: String
field :data, type: String
# NEW FIELD
field :note, type: String, default: "no note given so far!"
end
If you query your database you should get your default value for documents which haven't this field before your extension:
(rails console)
MyModel.first
#=> #<MyModel …other fields…, note: "no note given so far!">
I tested this with a fresh rails stack with a current mongoid on Ruby 1.9.2 - should work with other stacks, too.
More complicated/complex style:
If you didn't set a default value, you'll get nil for this new field.
app/models/my_model.rb
class MyModel
include Mongoid::Document
field :name, type: String
field :data, type: String
# NEW FIELD
field :note, type: String
end
(rails console)
MyModel.first
#=> #<MyModel …other fields…, note: nil>
Then you could set up a rake task and migration file like in this example:
lib/tasks/my_model_migration.rake:
namespace :mymodel do
desc "MyModel migration task"
task :migrate => :environment do
require "./db/migrate.rb"
end
end
db/migrate.rb:
olds = MyModel.where(note: nil)
# Enumerator of documents without a valid :note field (= nil)
olds.each do |doc|
doc.note = "(migration) no note given yet"
# or whatever your desired default value should be
doc.save! rescue puts "Could not modify doc #{doc.id}/#{doc.name}"
# the rescue is only a failsafe statement if something goes wrong
end
Run this migration with rake mymodel:migrate
.
This is only a starting point and you can extend this to a full mongoid migration engine.
The task :migrate => :environment do …
is necessary, otherwise rake won't load models.
Rails/Mongoid database migrations
Write a custom rake task to migrate the data as needed
Extracting, modelling and changing data model, with mongoid/mongodb
You do two things:
- Filter the users with db query instead of filtering in application
only fetch fields you need from db, rather than the whole user objects(assuming you have some other stuff in user, which you omitted here for brevity)
Competitor = Struct.new(:html_url, :description, :user)
competitors = []
User.where('watchlists.tags_array' => %w[ruby web framework]).
only(:nickname, :watchlists).each do |u|
u.watchlists.where(:tags_array => %w[ruby web framework]).each do |wl|
competitors << Competitor.new(wl.html_url, wl.description, u.nickname)
end
end
PS: Probably you do not want to use map
on User.all
, it will require a lot of memory if you have lots of heavy user documents. Also, you are not using the mapped users, but instead collecting results in the competitors
array yourself, so each
should work just fine.
rails mongoid dynamc model fails
Final solution:
Create all classes dynamically. While dynamically creating/instatiating classes I gave them a new name (Prefix+name of the model) so they do not override my initial class defintions which I need to seed the db (or for some internal processes). There is quite some database overhead with this: Reading the meta data for all classes including the associations and also dynamically create classes for all associated models or inheritances. So I only dynamically create a class and constantize it whenever the model changes (manipulating fields or associations/inheritance). For all other cases I use the existing class if already constantized.
How to update a boolean value with mongoid and rails?
I got it to work. I had to pass the job ID from the preview page to the controller again.
<%= form_for @job, url: '/jobs/publish/'+@job.id do |f| %>
And then revised the controller to:
def update
job = Job.find(params[:id])
job.publish = true
job.save!
redirect_to '/jobs'
end
And change the route to "patch":
patch '/jobs/publish/:id' => 'jobs#update'
Renaming field in Mongoid does not update field in class
When you run #rename
, you interact with MongoDB. The change of document structure is stored in the database. This method does not interact with ruby source code, you need to edit it by yourself.
Btw. I can't recall any ruby/rails method (besides ones in rake tasks and generators) that interacts with the source code stored in files.
Related Topics
Deleting Table from Schema - Rails
Multiple Robots.Txt for Subdomains in Rails
Augmenting a Model from an External Gem
Collect Values from an Array of Hashes
How to Send Mail with Rails Without a Template
How to Declare a Variable Shared Between Examples in Rspec
How to Get Request's Target Controller and Action with Rails 3
$Redis Global Variable with Ruby on Rails
How to Install Ruby Gems When Using Rvm
How to Solve the Update Bundler Warning in Rails When Deploying to Heroku
Rails: Your User Account Isn't Allowed to Install to the System Rubygems
Does Scala Scale Better Than Other Jvm Languages
How to Export a Ruby Array from My Heroku Console into CSV
Where Are the Gems When Ruby Compiled Manually in MAC Os X 10.6.8
Convert Unicode into Character with Ruby