MongoMapper - manually setting an ObjectId failing with "illegal ObjectID format" - ruby

I've got a simple model object:
class UserRating
include MongoMapper::EmbeddedDocument
key :idea_id, ObjectId
key :rating, Integer
end
I'm trying to set an Idea_Id on this object with:
user_rating.idea_id = ObjectId.new
This throws: "illegal ObjectID format"
This sure seems like simple code... The only oddity I am noticing is that ObjectID != ObjectId. That could just be a problem with the error message. Not sure. Very simple code. No idea why I can't make it work. If it helps, this is in the context of a Rails 3 Beta 4 project inside of a Cucumber test. I am hitting the mongodb daemon successfully, so there's not a weird connection issue. Would really appreciate any pointers.

MongoMapper has a proxy object called ObjectId - in this case, you want a BSON::ObjectID, which represents an ID as it is stored in mongodb itself.
You probably want:
key :idea_id, BSON::ObjectID, :index => true

No, you want ObjectId. When you assign that you'll want to pass an actual object id which gets generated for each MM model.
user_rating.idea_id = idea.id

Related

Accessing the value of custom field in redmine plugin

I am using Redmine 2.1 and I am writing a custom plugin. I am trying to access the value of a custom field on an issue.
def controller_issues_edit_before_save(context = {})
issue = context[:issue]
add_assignee(issue)
end
I am getting my issue then I pass it to a custom function.
private
def add_assignee(issue)
add_watcher_to_issue(issue, issue.custom_field_values {'bob'})
end
I don't seem able to get the value of my custom field bob. bob is a user field.
How do I get the value of my custom field?
I can't check it myself but the argument passed to issue.custom_field_values {'bob'} confuses me. it looks like you pass a block?!
Looked at this line I think custom_field_values is a hash so pass an expected key:
issue.custom_field_values('bob')

Creating new Datamapper resources (database entries) using .each

I want to take Google Custom Search API results and add them to a database using Datamapper.
I've managed to successfully set up and manually add some items to the database, so it seems like that is all set up correctly.
I'm using HTTParty to make the call the the Google API, which is returning JSON results. I then want to take that JSON and add each link into the database. I'mtrying to use .each as follows;
response["items"].each do |item|
i=DMapperModel.create(city: "London", link: item["link"])
puts i
puts i.saved?
end
Response is a variable holding the HTTParty::response, "items" and "link" are both subsets of the HTTParty::response.
puts i successfully puts the correct DataMapper resource (i.e. <#DMapperModel city: 'London', link: 'example.com'>)
puts i.saved? is a check to see if i saved to the database, at the moment this is returning false...
So it is successfully setting i to the DataMapper resource, but not saving it to the database for some reason, can anyone see where I'm going wrong?
Solved it myself!
I had the links parameter set as a string, which DataMapper sets at a default maximum length of 50 characters. All of the links I was trying to add were longer that 50 characters so the save was failing.
Resolved the problem by setting the maximum length of the link parameter to 2000 characters;
class CityLink
include DataMapper::Resource
property :id, Serial
property :city, String
property :link, String, *length: 2000*
end
I took the length of 2000 characters from this page on the DataMapper docs which is for the URI parameter type and links to this SO question.
Once I'd set this, the above .each method worked a trick.

Embedding documents in existing documents with the Ruby Driver for MongoDB

I'm trying to embed a document inside an existing document using the Ruby Driver.
Here's what my primary document looks like:
db = Mongo::Connection.new.db("Portfolios")
project_collection = db.collection("Projects")
new_Project = { :url => 'http://www.tekfolio.me/billy/portfolio/focus', :author => 'Billy'}
project_collection.insert(new_Project)
After I've created my new_project and added it to my project_collection I may or may not add another collection to the same document later called assets. This is where I'm stuck. The following code doesn't seem to do anything:
new_asset = { :image_url => 'http://assets.tekfolio.me/portfolios/68fbb25a-8353-41a8-a779-4bd9762b00f2/projects/13/assets/20/focus2.PNG'}
new_Project.assest.insert(new_asset)
I'm certain I've butchered my understanding of Mongodb and the Ruby driver and the embeded document concept and would appreciate your help getting me out of this wet paper bag I can't seem to get out of ;)
Have you tried just setting the value of asset without insert and instead using update?
new_Project["asset"] = new_asset
project_collection.update({"_id" => new_Project["_id"]}, new_Project)
I think , are you trying to "update" the new_project record with the asset
it doesn't work because then you are only updating the hash in ruby, not in mongo, you have to first get the reference to the object in mongo, update it, and then save it, check this info:
http://www.mongodb.org/display/DOCS/Updating+Data+in+Mongo
(if you can, you can assign the asset before inserting, and it should work)

Runtime changing model with mongodb/mongoid

I've to add several fields in a mongoid model, I know there is not migration with MongoDB but if I go on without dropping the DB, making rails to "regenerate" the DB entirely, it doesn't display or use the new fields at all !
What's the best way to go here ? Is there something softer than drop/reopen mongodb ?
Thanks in advance
luca
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.
It is a little ridiculous to say that you don't need migrations with mongodb or mongoid. Any sophisticated app needs to be refactored from time to time and that can mean pulling fields out of disparate documents into a new one.
Writing one off rake tasks is way less convenient and error prone than having migrations be part of your deploy script so that it always gets run on every environment.
https://github.com/adacosta/mongoid_rails_migrations brings AR style migrations to mongoid.
You might need them less often, but you will certainly need them as an app grows.
Below is a nice code example for data migration script with mongoid and the ruby mongo driver - to be used when your updated model no longer match production data.
http://pivotallabs.com/users/lee/blog/articles/1548-mongoid-migrations-using-the-mongo-driver
I whish we would stop using "no migrations with mongoid" as slogan. It'll turn people to MongoDB for the wrong reasons, and it's only partially true. No schema, true, but data still needs to be maintained, which IMO is harder with MongoDB than RDBMs. There are other, great reasons for choosing MongoDB and it depends on your problem.

Rails: ParameterFilter::compiled_filter tries to dup symbol

I'm running rails3 with rails exception-notifier gem. When an exception occurs, and an email should be sent, I'm getting an exception from the ParameterFilter class. I've found the problem in the rails source, and am not sure the best way to proceed.
The problem occurs in ActionDispatch::Http::ParameterFilter. In the compiled_filter method, an error occurs on line 38: key = key.dup when key is a symbol, because symbols are not duplicable. Here is the source:
def compiled_filter
...
elsif blocks.present?
key = key.dup
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end
I see that they only call dup on value when it is duplicable. If I patch the source to only call dup on key when key is duplicable, then my problem goes away. I'm assuming there is a reason why the author put that condition on value and not key, so I'm curious if someone out there has a better understanding of this code.
This error only occurs when you add a block to your filter params in application.rb. So, maybe there is a workaround for my original issue that does not require using a block here. If you're interested see my coworker's question Rails: Filter sensitive data in JSON parameter from logs
The key for which this is a problem is :action. This comes from rails and I don't know if there is any way to force it to be a string instead.
I filed a rails bug https://rails.lighthouseapp.com/projects/8994/tickets/6557-symbol-duplication-error-in-parameterfilter-compiled_filter and I have a patch ready that adds if key.duplicable? to the key.dup line, I'm looking for input on whether or not that is the right solution.
This looks like a bug in Rails. Either the key should be a string rather than a symbol, or the dup should be protected by duplicable?.
You should file a bug at https://rails.lighthouseapp.com/, including a minimal test case if possible.

Resources