Preventing Mongoid 4.0.0 model field coercion of id => _id - ruby-on-rails

I'm using Mongoid 4.0.0 with Rails 4. My models map tables in another application, and I have no control over the field names.
One of the models has a field named id, which is getting coerced into Mongo's _id field. For example, when I insert a document with an id value of "something" I get
{_id:"something", id:null}
instead of
{_id:ObjectId("<hexstring>"),id:"something"}
Is there any way to avoid this coercion, make Mongoid not conflate the two fields, and leave my id field alone?
As I said, renaming the id field is not an option.
Thanks!
[edited]
This is definitely not a MongoDB issue. It must be in Moped or (my guess) Mongoid.
I've tried changing the params key from :id to :_rid but this is still happening. I'm going to check out aliases, but from my first pass I don't think they're going to help -- they appear to go the wrong way.

This appears to be hardcoded into Moingoid and a pervasive assumption throughout. It's annoying enough, though, that I might come up with a patch to allow users to override the key field on a per-model basis.
Oh well.

Related

setting mongoid hash field values

I'm using Mongoid in a Rails project (both 4.0.x), and I've got a document with a hash field that stores some schema-less data.
class Thing
field :name, type: String
field :mass, type: Integer
field :info, type: Hash
end
With this setup, I can query for things, say, that have a key :endDate like so:
Thing.where("info.endDate"=>{'$exists'=>true})
And that's all nice and handy. Using a hash field for this :info field is nice because what I want to store doesn't have a fixed schema and varies from one thing to another.
Ok, but, I can't use the same dot syntax to $set key/value pairs in the :info hash. [1]
thing.set("info.endDate"=>Time.now)
Raises a Mongoid::Errors::UnknownAttribute error.
It tells me I'd have to include Mongoid::Attributes::Dynamic in my model to do this, but that doesn't seem right to me. The point of the hash field type seems to be to allow you to work with data that doesn't have a fixed schema. It doesn't seem like I should have to include a special "dynamic attributes" module to use hash fields.
So right now, I'm updating values using regular old [] syntax, and then calling save on the model, like so:
thing.info[:endDate] = Time.now
thing.save
But a lot of the time it happens that it would be nicer to just $set the value. Is there some other syntax for setting hash field values? Am I wrong about the above error message and Dynamic Attributes being wrong-headed? Am I stuck doing two step updates to hash fields for now?
[1] admittedly, I've recently migrated from mongomapper, and so my expectations of this syntax are partly set by having been able to do this previously in mongomapper.
The thing with Hash field is, it can be dynamic as much as you want. Therefore to prevent polluting your DB schema with unintended fields caused by bugs in your code this functionality is disabled by default.
No you are not stuck using 2-step updates for your hashes at all!
[],[]= are the shortcuts for read_attribute() and write_attribute() and should be used if you don't include Mongoid::Attributes::Dynamic. If you try to use $set without enabling dynamic attributes you will get a no-method error because it does not see your dynamic attributes as defined attributes.
If you'll read the source of Mongoid::Attributes::Dynamic then you'd find that this is required to add the dynamic attributes functionality.
To update the values by including Mongoid::Attributes::Dynamic you need to follow these steps:
thing = Thing.first
thing.set("info.endDate" => Time.now)
thing.reload # This will update the current variable
Otherwise if you need you can easily skip this and do the value update by 2-step method
I hope this sheds some light over your query.
Source:
Rails mongoid dynamic fields - no method error
Dynamic attributes with Rails and Mongoid
I think you pass parameter in wrong way. Replace arrow symbol with comma
You can change to this and it will work
thing.set("info.endDate", Time.now)

how to get title when table has type column

We have a simple site model with single table inheritance sites(id, type, title, address) where type can be "Home" or "office". When we were on Rails 2.3.5 we could do Site.last.title and it would give the title. However, on Rails 3.2.6, when we do Site.last.title it give us the value as the type column instead.
Is it possible to get the value of the title instead of the type?
If you are trying to get the newest value of a table, It is better to find it by created_at column. By default, using Site.last, Rails will search by primary key (ID), which is fine most of the time. However, if for any reason you need to change an ID on an existing record, your SQL will not return what you expect.
So, it is better to do something like:
Site.order("created_at").last.title
Regarding the problem you are facing, I think the problem is related to the type and not the title. Anyway, I recommend you to set the newest site in your controller and then call it in your view.
#controller
#site=Site.order("created_at").last
#view
#site.title
I hope it helps...

Rails Association Validations: The field, or the _id field?

One of the messier practices I have in Rails development is juggling validations of associated fields between validating the actual object (eg: validates_presence_of :related_object) and validating on the id column for that association (eg: validates_presence_of :related_object_id).
I figure I should probably start being a little more consistent with this, and before I commit to anything, I'm wondering if there's any advantage of either method over the other? I can't think of anything, but then I've been known to overlook stuff before. So, does it make any difference? Is there a convention re: what most developers do that I should abide by?
Any suggestions appreciated.
This question comes up every so often.
In most cases you will want to validate the presence of the actual associated object, not just verify that an id (which could well be invalid) has been set.
Validating association_id will also prevent you from creating the object with a new association record and saving both together.
Of course you have to check the presence of :object_id. If you check the presence of :object then this object will be fetched from your DB and then will be checked via simple blank?. I guess you won't be happy with additional DB hit.

Rails: how do I use question marks in a model?

We have a field in our mongodb database called "failed?", including the question mark. Sometimes when I access that field, I get the value in the database, and sometimes I get null. I'm looking to understand what should happen a little bit more in order to debug this. So, can you have a question mark in a field name in a model, like so:
field :failed?, :type => Boolean, :default => nil
or am I in for a world of trouble. Assuming I already have this in the database and have to work with it, how should I get the fields out.
Environment: Rails 3.1, JRuby, Mongoid.
It's most likely a Mongoid bug as question marks in field names are valid in MongoDB. If I had to take a guess, it could be a weird conflict with the automatic <field>? that are created by Mongoid.
The easiest way to work around this would be to try accessing it through the raw hash that is pulled out from MongoDB, you can access it with model.attributes["failed?"]. If you still have issues, then likely it's a MongoDB driver problem.

mongoid atomic updates in rails

i am having an issue with updating existing documents composite key fields in rails. the associated mongo query for my update_attributes statement seems to be correct, however the object cannot be found afterwards.
for example with an existing object with first_name "Jane" and last_name "Doe"... with my :key being :first_name, :last_name
i hit my update method with:
{"artist"=>{"last_name"=>"Doe", "first_name"=>"John"}, "commit"=>"Update Artist", "id"=>"jane-doe"}
def update
#artist = Artist.find(params[:id])
if #artist.update_attributes(params[:artist])
redirect_to #artist
end
end
which generates the mongo query: MONGODB app_database['artists'].update({"_id"=>"jane-doe"}, {"$set"=>{"_id"=>"john-doe", "first_name"=>"John"}})
which seems correct to me... but when i am redirected to that new artist, it complains about Document not found for class Artist with id(s) john-doe.
and in fact looking at my db from the mongo console, i still see Jane Doe in there. It is something to do with them being composite key fields, since i can update non-key fields just fine.
what am i missing here?
I tried this in an app of my own, and it looks like MongoDB simply doesn't currently allow you to modify the _id field as part of a $set operation (which is what Mongoid uses to perform updates). This is a strange restriction - I've been using Mongo for a year and a half now and I've never run into it.
So, a few options:
Stop using anything for your _id that might need to be changed later. I'd do this - it's a best practice anyway.
Whenever you need to make one of these _id changes, instead create a new record with the new _id attribute and delete the old one. This might get messy though, especially if you have other models that refer your Artist models by id.
File an issue with 10gen asking for this restriction to be lifted. They're very good about responding to users' concerns, but even if they agree, it'll probably take a while to be done.
File an issue with Mongoid to request support for these types of changes (Mongoid could conceivably handle the create + delete mechanism for you), but honestly, it's the kind of edge case that's probably not worth the extra time and code for them to support. It'd be nice if Mongoid raised an error when you tried to do an update like this, at the very least.

Resources