Mongoid giving error while saving field with particular name - ruby-on-rails

I am using mongoid in rails app. rails 3.0.10 ruby 1.9.2p0
When I am trying to use field like "test", "link", "desc" etc.
say
Content.new(:test => 'ggg')
Content.new(:link => 'ggg')
Content.new(:desc => 'ggg')
Content is model which uses "Mongoid::Document"
it gives following error. (this error is for field "test")
I think mongoid uses some library which contents above field names as functions which
might create problem. Is there any way to come around this problem.
ArgumentError: wrong number of arguments (0 for 2..3)
from /usr/lib/ruby/gems/1.9.1/gems/activemodel-3.0.10/lib/active_model/dirty.rb:155:in `test'
from /usr/lib/ruby/gems/1.9.1/gems/activemodel-3.0.10/lib/active_model/dirty.rb:155:in `attribute_will_change!'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes.rb:102:in `block (2 levels) in write_attribute'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes.rb:100:in `tap'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes.rb:100:in `block in write_attribute'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes.rb:170:in `assigning'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes.rb:98:in `write_attribute'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes/processing.rb:95:in `process_attribute'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes/processing.rb:25:in `block in process'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes/processing.rb:23:in `each_pair'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/attributes/processing.rb:23:in `process'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/document.rb:128:in `block in initialize'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/relations/builders.rb:47:in `building'
from /usr/lib/ruby/gems/1.9.1/gems/mongoid-2.2.4/lib/mongoid/document.rb:125:in `initialize'
from (irb):1:in `new'
from (irb):1
from /usr/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in `start'
from /usr/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in `start'
from /usr/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/commands.rb:23:in `<top (required)>'
from /home/harshal/simple-cms/branches/1.0/script/rails:6:in `require'
from /home/harshal/simple-cms/branches/1.0/script/rails:6:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'

Using the latest everything, ruby(1.9.3), rails(3.2.3), mongoid(2.4.7) I tried the following things:
Model with no set fields, all dynamic:
class Content
include Mongoid::Document
end
Rails console:
1.9.3p125 :011 > c = Content.new(:test => "test", :link=> "link", :desc => "desc")
=> #<Content _id: 4f7f49f5add3617fae000003, _type: nil, test: "test", link: "link", desc: "desc">
1.9.3p125 :012 > c.save
=> true
1.9.3p125 :013 > Content.first
=> #<Content _id: 4f7f49f5add3617fae000003, _type: nil, test: "test", link: "link", desc: "desc">
1.9.3p125 :014 >
Model with all fields statically set:
class Content
include Mongoid::Document
field :test, :type => String
field :link, :type => String
field :desc, :type => String
end
Rails console again:
Loading development environment (Rails 3.2.3)
1.9.3p125 :001 > c = Content.new
=> #<Content _id: 4f7f4652add3617ec4000001, _type: nil, test: nil, link: nil, desc: nil>
1.9.3p125 :002 > c.test = 'tyler'
=> "tyler"
1.9.3p125 :003 > c.save
=> true
1.9.3p125 :004 > Content.first
=> #<Content _id: 4f7f4652add3617ec4000001, _type: nil, test: "tyler", link: nil, desc: nil>

Related

How to monkey patch Commontator::Comment (or any rails engine)?

I just recently learned the term monkey patching, so I'm not sure if I have it right.
I am using the Commontator gem to provide commenting functionality on my Blog (Monologue::Post models) and my other models. I ran into an issue where I was trying to get the parent object from my comment (ie, what was commented on). It looks like I would have to do three joins. Rather than call that in my controller, I thought I could extend the gem's model to have a function comment_parent that would return the parent model.
I have this:
# config/initializers/comment_model_extenders.rb
module Commontator
class Comment < ActiveRecord::Base
def comment_parent
# do some magic
"return parent here"
end
end
end
I must be doing it wrong, because I am getting this error:
irb(main):010:0> c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):011:0> c.comment_parent
NoMethodError: undefined method `comment_parent' for #<Class:0xab743d0>
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
from (irb):11
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
EDIT:
Based off of Fredrick's comments, I changed my code to be
...
def self.comment_parent
...
but the output is as follows:
irb(main):022:0* c=Commontator::Comment
=> Commontator::Comment(id: integer, creator_type: string, creator_id: integer, editor_type: string, editor_id: integer, thread_id: integer, body: text, deleted_at: datetime, cached_votes_up: integer, cached_votes_down:
integer, created_at: datetime, updated_at: datetime)
irb(main):023:0> c.comment_parent
=> "return parent here"
irb(main):024:0> test = c.find(1)
Commontator::Comment Load (35.7ms) SELECT "commontator_comments".* FROM "commontator_comments" WHERE "commontator_comments"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Commontator::Comment id: 1, creator_type: "User", creator_id: 2, editor_type: nil, editor_id: nil, thread_id: 2, body: "Love this parser.", deleted_at: nil, cached_votes_up: 0, cached_votes_down: 0, created_at: "201
5-02-12 22:04:48", updated_at: "2015-02-12 22:04:48">
irb(main):025:0> test.comment_parent
NoMethodError: undefined method `comment_parent' for #<Commontator::Comment:0xad08a10>
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activemodel-4.1.8/lib/active_model/attribute_methods.rb:435:in `method_missing'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4.1.8/lib/active_record/attribute_methods.rb:213:in `method_missing'
from (irb):25
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:90:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/console.rb:9:in `start'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:69:in `console'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/railties-4.1.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Looking at the library, your parent object has_one :thread, :as => :commontable, while the thread has_many :comments.
So, inside a Comment, thread.commontable should get you the other way around back up to your original parent.
Based on the comments, here is my solution:
In general, I wanted it to be called as an instance method, so my original code was correct. I was just calling it wrong. To call an instance method, do one of these:
Model.new.custom_method
or
my_model = Model.new #or .find(n)
my_model.custom_method
For my specific case, I found this solution:
module Commontator
class Comment < ActiveRecord::Base
def comment_parent
# do some magic
thread = Commontator::Thread.find(self.thread_id)
parent_class = thread.commontable_type.camelize.constantize
parent_class.find(thread.commontable_id)
end
end
end

How to solve the method missing error in rails console

I've a model Dish and PriceDeal as follows
class Dish < ActiveRecord::Base
has_one :price_deal
end
class Dish < ActiveRecord::Base
belongs_to :dish
end
In rails console, I want to retrive the discountPercent value like this.
1.9.2p290 :130 > pd=PriceDeal.find(17)
=> #<PriceDeal id: 17, name: "deal1", description: "my deal1", discountPercent: 20.0, discountCash: nil, dish_id: 2, created_at: "2012-03-22 07:42:08", updated_at: "2012-04-16 11:16:49">
1.9.2p290 :131 > pd.discountPercent
=> 20.0
I got the expected result.
But when I try to get the value like this,
1.9.2p290 :132 > pd1 = PriceDeal.where(:dish_id => 2)
=> [#<PriceDeal id: 17, name: "deal1", description: "my deal1", discountPercent: 20.0, discountCash: nil, dish_id: 2, created_at: "2012-03-22 07:42:08", updated_at: "2012-04-16 11:16:49">]
1.9.2p290 :133 > pd1.discountPercent
NoMethodError: undefined method `discountPercent' for #<ActiveRecord::Relation:0xa134958>
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/activerecord-3.0.11/lib/active_record/relation.rb:374:in `method_missing'
from (irb):133
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands/console.rb:44:in `start'
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands/console.rb:8:in `start'
from /home/ragunathjawahar/.rvm/gems/ruby-1.9.2-p290#rails3tutorial/gems/railties-3.0.11/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
I got error,
How to get the value of discountPercent from pd1.
Thanks.
The reason why this is happening is because when you use where, you get back not a single object of type PriceDeal, but you get an object of type ActiveRecord::Relation, which for all intents and purposes is an array.
Notice how you got:
[#<PriceDeal id: 17, name: "deal1", ... >]
Instead of just:
#<PriceDeal id: 17, name: "deal1", ... >
The braces ([]) mean that it's an array. So you'll have to do this:
pd1.first.discountPercent
The reason why the where method returns an array is because you can have multiple items returned. Imagine doing:
PriceDeal.where("discountPercent >= 0")
You'd probably get a lot of records from that.
pd=PriceDeal.find(17)
It will return only one particular column.so you will not get no method error.
when you are using Modelname.where("conditions").The results will be array.so you will get no method error.Because your method is not present to array.

Can't do geo query on embedded document using Mongoid and Geocoder

(Ruby 1.9.3, MongoDB 2.0.4, Rails 3.2, Mongoid 2.4, Geocoder 1.1.1)
I have the following models:
class Company
include Mongoid::Document
embeds_one :office
index [[ "office.coordinates", Mongo::GEO2D ]]
end
class Office
include Mongoid::Document
include Geocoder::Model::Mongoid
geocoded_by :address
field :city, :type => String
field :state, :type => String
field :coordinates, :type => Array
embedded_in :company
after_validation :geocode
def address
"#{city}, #{state}"
end
end
I do this in the console:
> c = Company.new
=> #<Company _id: 4f885aa56d20f03898000003, _type: nil>
> c.office = Office.new(:city => "San Francisco", :state => "CA")
=> #<Office _id: 4f885ab66d20f03898000004, _type: nil, city: "San Francisco", state: "CA", coordinates: nil>
> c.save
=> true
So far so good. But then I try to retrieve the company by doing a geoquery on its embedded document (office):
> Company.where(:office.near => Company.first.office.to_coordinates).first
Mongo::OperationFailure: can't find special index: 2d for: { office: { $near: [ -122.4194155, 37.7749295 ] } }
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongo-1.6.2/lib/mongo/cursor.rb:144:in `next'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongo-1.6.2/lib/mongo/collection.rb:288:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/master.rb:25:in `block in find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/retry.rb:29:in `retry_on_connection_failure'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/master.rb:24:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collection.rb:60:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/contexts/mongo.rb:203:in `first'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/criteria.rb:45:in `first'
from (irb):2
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:47:in `start'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:8:in `start'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
What am I doing wrong? I've run rake db:mongoid:create_indexes.
You need to run the query against the embedded field:
Company.where(:'office.coordinates'.near => Company.first.office.to_coordinates).first
If you want to leverage the near scope created by the geocoder gem under Office, you can do something like the following:
# in Company.rb
self.near(office, radius = 20, conditions = {})
self.where(conditions).tap do |criteria|
near_criteria = Office.scopes[:near].conditions.call(office, radius)
criteria.selector[:'office.coordinates'] = near_criteria.selector[:coordinates]
end
end
This creates Company#near which takes an Office object. It will inject the query created by the Office#near scope into a query for a company.

Rails 3.1: Creating objects via .build seems to conflict with validates_presence_of

I am having trouble combining a validation of a foreign key field, and making use of the .build method to create objects. See the classes below.
class Parent < ActiveRecord::Base
belongs_to :family
has_one :family_user
validates_presence_of :name
validates_associated :family
validates_presence_of :family_id
end
class Family < ActiveRecord::Base
belongs_to :organization
has_many :parents
...
end
This generally works fine, but in the app I want to use the build method. For example, the following code in both a spec and in the rails console fails because it is looking for a family_id on the Parent record.
fam = Family.new(:organization_id => 1)
fam.children.build(:name => "Billy Jones")
fam.parents.build(:name => "Mister Jones")
fam.save!
Without validates_presence_of :family_id this code works, and indeed a family_id is properly recorded.
Question: is there a way to validate that a family_id is indeed recorded, while also being able to use .build?
For reference, an error in the console is:
ruby-1.9.2-p290 :082 > fam = Family.new(:organization_id => 1)
=> #<Family id: nil, organization_id: 1, created_at: nil, updated_at: nil, url_token: nil>
ruby-1.9.2-p290 :083 > fam.children.build(:name => "Billy Jones")
=> #<Child id: nil, family_id: nil, name: "Billy Jones", gender: nil, birth_date: nil, desired_start_date: nil, application_date: nil, notes: nil, custom1: nil, custom2: nil, custom3: nil, custom4: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p290 :084 > fam.parents.build(:name => "Mister Jones")
=> #<Parent id: nil, family_id: nil, name: "Mister Jones", address: nil, phone: nil, email: nil, notes: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p290 :085 > fam.save!
ActiveRecord::RecordInvalid: Validation failed: Parents family can't be blank
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/validations.rb:56:in `save!'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/transactions.rb:246:in `block in save!'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/transactions.rb:208:in `transaction'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/activerecord-3.1.1/lib/active_record/transactions.rb:246:in `save!'
from (irb):85
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/railties-3.1.1/lib/rails/commands/console.rb:45:in `start'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/railties-3.1.1/lib/rails/commands/console.rb:8:in `start'
from /Users/business/.rvm/gems/ruby-1.9.2-p290#rails311/gems/railties-3.1.1/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
ruby-1.9.2-p290 :086 >
I would understand it the same way, at least upon initial reading the code that you have.
Maybe you can try this alternate solution:
http://forums.pragprog.com/forums/74/topics/732
Remove
validates_associated :family
validates_presence_of :family_id
and try this
validates_presence_of :family
Hope this helps.

to_xml Doesn't Work on Objects Returned Through Rails ActiveRecord habtm Reference

I have two rails active record classes, School and Instructor linked by a has_and_belongs_to_many relationship.
I need to query my instructors_controller for instructors for a particular school and return an xml format response. Therefore, in the index method I have this code fragment:
school = School.find(params[:school_id])
#instructors = school.instructors
and later:
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #instructors }
format.json { render :json => #instructors }
end
But it doesn't work. Look at this intriguing but baffling sequence:
ruby-1.9.2-p180 :023 > Instructor.all.first
=> #<Instructor id: 1, name: "Mrs. Smith", instructor_type_id: 1, created_at: "2011-07-24 18:19:40", updated_at: "2011-07-24 18:19:40">
ruby-1.9.2-p180 :026 > Instructor.all.first.class
=> Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime)
ruby-1.9.2-p180 :024 > School.first.instructors.first
=> #<Instructor id: 1, name: "Mrs. Smith", instructor_type_id: 1, created_at: "2011-07-24 18:19:40", updated_at: "2011-07-24 18:19:40">
ruby-1.9.2-p180 :025 > School.first.instructors.first.class
=> Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime)
ruby-1.9.2-p180 :021 > Instructor.all.first.to_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<instructor>\n <created-at type=\"datetime\">2011-07-24T18:19:40Z</created-at>\n <id type=\"integer\">1</id>\n <instructor-type-id type=\"integer\">1</instructor-type-id>\n <name>Mrs. Smith</name>\n <updated-at type=\"datetime\">2011-07-24T18:19:40Z</updated-at>\n</instructor>\n"
Now for the punchline:
ruby-1.9.2-p180 :019 > School.first.instructors.first.to_xml
NoMethodError: undefined method `type' for nil:NilClass
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activesupport-3.0.9/lib/active_support/whiny_nil.rb:48:in `method_missing'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:230:in `compute_type'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:22:in `initialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `new'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `block in serializable_attributes'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `each'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `map'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `serializable_attributes'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:116:in `add_attributes_and_methods'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:103:in `block in serialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `call'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `_nested_structures'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:58:in `method_missing'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:31:in `tag!'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:102:in `serialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:175:in `to_xml'
from (irb):19
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'ruby-1.9.2-p180 :020 > Instructor.all.first.to_xml
What's going on here ?
Edit: Well, switching from xml to json solved the problem, (to_json does not exhibit the same strangeness as to_xml here), although I would still like to know the explanation for the above behavior.
Also, as I am relatively new to Rails, is there a better way to do what I want to do here ?
to_xml() tries to define a type attribute for each model attribute. For example, a User model with an age (INT) attribute will have: <age type="integer">42</age>. This type information is not encoded in JSON, which is why to_json() works for you. Add this method to your Instructor model:
def to_xml(options = {})
to_xml_opts = {:skip_types => true} # no type information, not such a great idea!
to_xml_opts.merge!(options.slice(:builder, :skip_instruct))
# a builder instance is provided when to_xml is called on a collection of instructors,
# in which case you would not want to have <?xml ...?> added to each item
to_xml_opts[:root] ||= "instructor"
self.attributes.to_xml(to_xml_opts)
end
This would however make your XML devoid of any type information - not good if someone has a JAVA REST client. A better strategy would be to filter self.attributes.slice(*keys).to_xml(to_xml_opts) where keys is an array of model attributes you want in the XML.

Resources