Rails 3: NameError with association - ruby-on-rails

I am brand new to Ruby, and have just now touched upon associations. Here are my models:
class Subject < ActiveRecord::Base
has_many :pages
scope :visible, where(:visible => true)
scope :invisible, where(:visible => false)
scope :search, lambda {|query| where(["name LIKE ?", "%#{query}%"])}
end
class Page < ActiveRecord::Base
belongs_to :subject
has_many :sections
has_and_belongs_to_many :editors, :class_name => "AdminUser"
end
My tutorial (psh.. what does it know) told me to type "subject.pages", after finding the first subject, like this:
Loading development environment (Rails 3.0.10)
irb(main):001:0> Subject.find(1)
=> #<Subject id: 1, name: "Initial Subject", position: 1, visible: true, created
_at: "2010-09-29 20:51:09", updated_at: "2010-09-29 21:07:42">
irb(main):002:0> subject.pages
NameError: undefined local variable or method `subject' for main:Object
from (irb):2
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds/console.rb:44:in `start'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds/console.rb:8:in `start'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
irb(main):003:0>
According to the tutorial, it should have came back with an empty array. I have searched Google, this site, Yahoo Answers, everywhere for a possible explanation. Everything just seems to be correct to me. Can anyone help?

You need to store the result of Subject.find(1) into a variable before using it, just like you would with any language:
subject = Subject.find(1)
Then you can do subject.pages. Otherwise subject doesn't refer to anything.
Alternatively, you can use _ to refer to the return value of the last expression. So you could type Subject.find(1) and then _.pages.
If you're new to Ruby, though, I recommend going through this and perhaps this tutorial, and if you're feeling brave, this guide.

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.

Writing new embedded document in Mongoid fails mysteriously

I'm trying to embed a new document in a previously existing document. When the object was created, the root document looked like this:
class MongoPoll
include Mongoid::Document
embeds_one :region_count, :as => :voteable, :class_name => 'VoteCount'
I've added a few new embedded documents of the same class:
embeds_one :browser_count, :as => :voteable, :class_name => 'VoteCount'
embeds_one :os_count, :as => :voteable, :class_name => 'VoteCount'
The VoteCount class looks like:
class VoteCount
include Mongoid::Document
embedded_in :voteable, :polymorphic => true
When I create new documents from scratch, I create the embedded documents in a before_create handler, and it works fine:
self.region_count = VoteCount.new
self.browser_count = VoteCount.new
self.os_count = VoteCount.new
However, for migrating my old documents, I try to do the same assignment (poll.os_count = VoteCount.new; poll.save) and it fails silently for os_count (but oddly not for browser_count). When I try saving using update_attribute or poll['os_count'] = VoteCount.new from rails console, I get stacktraces that look like the following:
BSON::InvalidDocument: Cannot serialize an object of class VoteCount into BSON.
from /Library/Ruby/Gems/1.8/gems/bson-1.4.0/lib/../lib/bson/bson_c.rb:24:in `serialize'
from /Library/Ruby/Gems/1.8/gems/bson-1.4.0/lib/../lib/bson/bson_c.rb:24:in `serialize'
from /Library/Ruby/Gems/1.8/gems/mongo-1.4.0/lib/../lib/mongo/collection.rb:426:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/master.rb:19:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/retry.rb:29:in `retry_on_connection_failure'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/master.rb:18:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collection.rb:149:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/operations/update.rb:45:in `persist'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:25:in `prepare'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:414:in `_run_update_callbacks'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `send'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `run_callbacks'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:24:in `prepare'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:414:in `_run_save_callbacks'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `send'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `run_callbacks'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:23:in `prepare'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/operations/update.rb:43:in `persist'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence.rb:86:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence.rb:151:in `save'
from (irb):5
Any idea what might be wrong here?

Rails: Caching classes ignores mixin

I have extended the ActiveRecord::Base class as follows:
lib/activerecord_ext.rb:
class ActiveRecord::Base
named_scope(
:recent,
:conditions => ['created_at > ?', (Time.new - 3.day)],
:order => 'created_at DESC',
:limit => 5
)
end
In config/environment.rb:
require "activerecord_ext"
This works fine until class caching is enabled. When I set
config.cache_classes = true
I get this error:
>> Person.recent
NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.call
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.3/lib/active_record/named_scope.rb:102:in `recent'
from (irb):1
I assume I'm doing something wrong with the inclusion of the extension. Any help would be greatly appreciated.
Is require 'activerecord_ext' before or after the config.cache_classes = true line? In any case, try putting require 'activerecord_ext' in an initializer instead.

Resources