MongoMapper - Updating existing records with new keys - ruby-on-rails

When adding a key to an existing model (with existing data) via MongoMapper, I can create new documents with the new key but when trying to access existing documents using that same key it fails stating that it's an "undefined method."
I was wondering if anyone had any insight.
Thanks in advance!
(Yes, these examples are truncated.)
- model.rb -
key :key_1
key :key_2
- would return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- model.rb (updated version) -
key :key_1
key :key_2
key :key_3
- would still only return -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
- but if a new doc is created -
#<Model _id: BSON::ObjectID('4ba821abebddb9094c000001'), key_1: "test", key_2: "test">
#<Model _id: BSON::ObjectID('7ba131abedaab9094c007482'), key_1: "test", key_2: "test", key_3: "test">
This would be fine except for the fact that I receive a method undefined error when trying to access :key_3 for the first document.
Rails 2.3.4
MongoMapper 0.7.4

I'm not seeing this behavior at all, even when interacting with an object instantiated before I updated the class. When running the following in irb, I have no errors:
>> gem 'mongo_mapper', '0.7.4'
=> true
>> require 'mongo_mapper'
=> true
>> MongoMapper.database = 'test'
=> "test"
>> class Foo
>> include MongoMapper::Document
>> key :something
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f8f938 #default_value=nil, #type=nil, #name="something", #options={}>
>> f = Foo.new(:something => 'thing')
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.save
=> true
>> f
=> #<Foo _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> class Foo
>> key :something_else
>> end
=> #<MongoMapper::Plugins::Keys::Key:0x101f6ad90 #default_value=nil, #type=nil, #name="something_else", #options={}>
>> f
=> #<Foo something_else: nil, _id: ObjectID('4c4dc9af712337447c000001'), something: "thing">
>> f.something_else
=> nil
Since it seems like you're having an unusual problem, more details of your use-case would be helpful. Could you please give us a more complete code example? If you've got proprietary stuff in the code that's failing, pare it down to the minimum case required to still have it fail and post the complete declarations of your models and the code you're using to access them.

Use the set command...
#model.set(:key_3 => "VALUE...")
#model.reload
#model.key_3 # => "VALUE..."
#model.save
This code will create a new field for your model, confirm that you already did defined with the new key:
key :key_3
Enjoy,

Related

The mongoid function "update_attribute" causes all attributes to be re-ordered alphabetically

Following up on this 1 year old post:
Mongodb mongoid model attributes sorted by alphabetical order not insertion order
I have a rails 3.2.8 application that uses mongoid v. 3.0.0. My application occasionally uses the "update_attribute" function on a database object (e.g. a product), but when it does all attributes gets reordered alphabetically.
When I duplicate this in the console, it looks like this:
1.9.3-p385 :001 > product = Product.find("5156bc9b83c3368121000008")
=> [#<Product _id: 5156bc9b83c3368121000008, _type: nil, product_number: "123", product_name: "Some product name", long_description: "<P>Some long product description.</P>", vendor_number: "abc", language_i_d: "1234", currency_i_d: "USD", category_number: "1", image_link: "http://some-external-website.com/image-path.jpg", original_id: "123456">]
1.9.3-p385 :002 > product.update_attribute(:image_link, "http://my-own-website.com/image-path.jpg")
=> true
1.9.3-p385 :003 > exit
I now fire up the console again (for some reason I need to exit and re-open the console before the new order is displayed):
1.9.3-p385 :001 > product = Product.find("5156bc9b83c3368121000008")
=> [#<Product _id: 5156bc9b83c3368121000008, _type: nil, category_number: "1", currency_i_d: "USD", image_link: "http://my-own-website.com/image-path.jpg", language_i_d: "1234", long_description: "<P>Some long product description.</P>", original_id: "123456", product_name: "Some product name", product_number: "123", vendor_number: "abc">]
Does anyone know how to avoid this reordering?
This isn't mongoid's fault. If an update causes a document to grow and mongo had to move the document as a result then mongodb itself may reorder the document's fields (see docs and a jira issue where this is described as normal)

RSpec/Mongoid inheritance of defaults completely different result in test/development

This is one of those ones that makes you think you're going insane...
I have a class Section, and a DraftSection that inherits from it:
(Trimmed for brevity)
class Section
include Mongoid::Document
belongs_to :site
field :name, type: String
end
And
class DraftSection < Section
field :name, type: String, default: "New Section"
end
All simple stuff... console proves (again, trimmed for brevity):
004 > site = Site.first
=> #<Site _id: initech, name: "INITECH">
005 > site.sections.build
=> #<Section _id: 1, site_id: "initech", name: nil>
006 > site.draft_sections.build
=> #<DraftSection _id: 2, site_id: "initech", name: "New Section">
As you can see - the draft section name correctly defaults to "New Section" as it is overridden in the subclass.
Now when I run this spec:
describe "#new" do
it "should return a draft section" do
get 'new', site_id: site.id, format: :json
assigns(:section).should == "Something..."
end
end
Which tests this controller method:
def new
#section = #site.draft_sections.build
respond_with #section
end
Which fails (as expected), but with this:
Failure/Error: assigns(:section).should == "Something..."
expected: "Something..."
got: #<DraftSection _id: 1, site_id: "site-name-4", name: nil> (using ==)
What gives???
Update:
I figured it might be an issue with the different environment settings, so I looked at the mongoid.yml config file and saw this in the options:
# Preload all models in development, needed when models use
# inheritance. (default: false)
preload_models: true
I added it to the test environment settings too, but still no joy :(
Update 2 - the plot thickens...
Thought I'd try loading up the console in the test environment and trying the same as before:
001 > site = Site.first
=> #<Site _id: initech, name: "INITECH">
002 > site.draft_sections.build
=> #<DraftSection _id: 1, site_id: "initech", name: "New Section">
WTF?
Ok, no one's listening, but I'll post the solution here for future reference anyway...
For some reason, some time ago I had a debug session that meant I had left this code in my Spork.each_run block
# Reload all model files when run each spec
# otherwise there might be out-of-date testing
# require 'rspec/rails'
Dir["#{Rails.root}/app/controllers//*.rb"].each do |controller|
load controller
end
Dir["#{Rails.root}/app/models//*.rb"].each do |model|
load model
end
Dir["#{Rails.root}/lib//*.rb"].each do |klass|
load klass
end
This was causing the models to get reloaded on each run of a spec. Not surprisingly, this screwed up the way the classes were set up in memory whilst the specs were running.
Definitely explains why it was such a hard one to debug...
So for future googlers with similar inheritance problems in Rspec only - make sure that there's nothing reloading models anywhere in the test stack.

Rails Active Record ID vs. Object ID + Active::Relation

I've been receiving messages like this:
warning: Object#id will be deprecated; use Object#object_id
I read and attempted the tricks from Ruby Object#id warnings and Active Record without success:
108-125-94-123:toptickets johnnygoodman$ rails c
Loading development environment (Rails 3.0.3)
>> ticket_id = 8899
=> 8899
>> ticket = Ticket.where(:number => ticket_id)
=> [#<Ticket id: 97, name: "Set Up API to Feed Customer Info into Bronto ", number: "8899", category_id: 15, created_at: "2011-01-31 21:24:29", updated_at: "2011-01-31 21:24:29", position: 20>]
>> ticket.id
(irb):3: warning: Object#id will be deprecated; use Object#object_id
=> 2175680980
>> ticket[:id]
TypeError: Symbol as array index
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `[]'
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `send'
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.3/lib/active_record/relation.rb:363:in `method_missing'
from (irb):4
>> ticket.class
=> ActiveRecord::Relation
I'd expect that when I queried for ticket it would be of class ActiveRecord::Base. I'm not sure what to do to get that going or if its the direction I should head in.
Goal: Query for a ticket, print its id. In the example above, the id's value should be 97.
ticket = Ticket.where(:number => ticket_id) returns an ActiveRecord::Relation (which when evaluated in IRB, performs the database query and returns an array of tickets). So ticket.id is trying to perform .id on the entire array of tickets, not one actual ticket.
Maybe you only want the first result?
>> ticket = Ticket.where(:number => ticket_id).first
>> puts ticket.id
=> 97

Strange problem with activerecord fetch/find with column name 'changes' in a RAILS 2.3.8 model

How is this possible?
Loading development environment (Rails 2.3.8)
>> wq = Wq.first(:conditions =>['widget_id=? AND qs_id=?',1,1])
=> #<Wq id: 1, widget_id: 1, qs_id: 1, operator: 0, requirements: "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2", changes: "1", route: 2, created_at: "2010-09-07 08:11:05", updated_at: "2010-11-24 10:25:53", body: "Which specific area of gyt are you aiming to addres...", options: "['xyz','pqr']", input_type: nil, status: 1>
>> wq.changes
=> {}
>> wq.changes
=> {}
>> wq.requirements
=> "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2"
>> wq.changes
=> "1"
Why is wq.changes coming as null initially and then after logging wq.requirements, wq.changes seems to come fine?
All necessary fields that are being fetched are withing a attr_accessible in the model.
I am not able to understand this situation, please help all you rails gurus.
The attribute name 'changes' conflicts with the AR::Dirty functionality. You should probably pick a different name for that column.
Here's the rails3 api docs for Dirty:
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
In rails2 it's in ActiveRecord rather than ActiveModel.
If you aren't able to rename the column, you could work around the issue by calling #model_obj[:changes] instead.
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L1466

Ruby on rails: virtual method that modifiyng model attributes with help of << couldn't save that attribute

There is model Ratification with attribute comment (of type text)
def Ratification < ActiveRecord::Base
attr_accessor :add_comment
def add_comment=(text)
self.comment ||= ""
self.comment << "\r\n" + text
end
end
And if I use add_comment= it is ok before I save the object. After save comment changes was dropped.
>> r = Ratification.last
Ratification Load (0.6ms) SELECT * FROM `ratifications` ORDER BY ratifications.id DESC LIMIT 1
=> #<Ratification id: 8, user_id: 686, comment: "dasads", created_at: "2010-06-25 13:16:24", updated_at: "2010-06-25 13:38:36">
>> r.comment
=> "dasads"
>> r.add_comment="text"
=> "text"
>> r.comment
=> "dasads\r\ntext"
>> r.save
SQL (0.7ms) BEGIN
SQL (0.2ms) COMMIT
=> true
>> r.reload
Ratification Load (1.6ms) SELECT * FROM `ratifications` WHERE (`ratifications`.`id` = 8)
=> #<Ratification id: 8, user_id: 686, comment: "dasads", created_at: "2010-06-25 13:16:24", updated_at: "2010-06-25 13:38:36">
>> r.comment
=> "dasads"
Why?!
Rails 2.3.8
Ruby 1.8
Hrrrm...that IS weird, I'm seeing similar behavior from my rails app when I try to do:
#s.name << "test"
and then reload...the original name is getting reset!
HOWEVER, if I do #s.name += "test"
then even after reloading, the new name is saved.
I'm not sure why << is behaving like that, but I usually default to += in all cases, so I've never noticed it before. Does changing to += help you?
Edit: Looking at the API, maybe it's because << modifies the original string, whereas + or += makes a NEW string, that contains the old one? Maybe rails somehow only saves things that it has marked as new (rather than modified?)

Resources