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

(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.

Related

Rails Create method Validation Error with one to one association

I have been learning ruby on rails from Coursera and am specifically at the one to one to one association module. I was trying to emulate the one to one association example in the tutorial on my own system however i get the ActiveRecord::RecordInvalid error. This is what i have done to reach this point:
1) rails g model person first_name last_name
2) rake db:migrate
3) rails g model personal_info height:float weight:float person references
4) rake db:migrate
5) Migration 20160725143537_create_people.rb has the following code:
class CreatePeople < ActiveRecord::Migration[5.0]
def change
create_table :people do |t|
t.string :first_name
t.integer :age
t.string :last_name
t.timestamps
end
end
end
6) Migration 20160727184247_create_personal_infos.rb has the following code:-
class CreatePersonalInfos < ActiveRecord::Migration[5.0]
def change
create_table :personal_infos do |t|
t.float :height
t.float :weight
t.references :person, foreign_key: true
t.timestamps null: false
end
end
end
7) The code in person.rb is as follows:
class Person < ApplicationRecord
has_one :personal_info
end
8) The code in personal_info.rb is as follows:-
class PersonalInfo < ApplicationRecord
belongs_to :person
end
9) The code in seeds.rb is as follows:-
Person.destroy_all
Person.create! [
{first_name: "Kalman", last_name: "Smith", age: 33, login: "kman", pass: "abc123"},
{first_name: "John", last_name: "Whatever", age: 27, login: "john1", pass: "123abc"},
{first_name: "Michael", last_name: "Smith", age: 15, login: "mike", pass: "not_telling"},
{first_name: "Josh", last_name: "Oreck", age: 57, login: "josh", pass: "password1"},
{first_name: "John", last_name: "Smith", age: 27, login: "john2", pass: "no_idea"},
{first_name: "Bill", last_name: "Gates", age: 75, login: "bill", pass: "windows3.1"},
{first_name: "LeBron", last_name: "James", age: 30, login: "bron", pass: "need more rings"},]
10) Now i go to the rails console (rails c) and type the following:
pi1 = PersonalInfo.create!(height:6.2, weight:220.0). This is when i get the aforementioned error which looks like this:
irb(main):002:0> pi1 = PersonalInfo.create!(height:6.2, weight:220.0)
(0.0ms) begin transaction
(0.0ms) rollback transaction
ActiveRecord::RecordInvalid: Validation failed: Person must exist
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/validations.rb:78:in `raise_validation_error'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/validations.rb:50:in `save!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/attribute_methods/dirty.rb:30:in `save!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/transactions.rb:324:in `block in save!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/transactions.rb:395:in `block in with_transaction_returning_status'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:232:in `block in transaction'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/transaction.rb:189:in `within_new_transaction'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:232:in `transaction'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/transactions.rb:211:in `transaction'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/transactions.rb:392:in `with_transaction_returning_status'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/transactions.rb:324:in `save!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/suppressor.rb:45:in `save!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-5.0.0/lib/active_record/persistence.rb:51:in `create!'
from (irb):2
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/railties-5.0.0/lib/rails/commands/console.rb:65:in `start'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/railties-5.0.0/lib/rails/commands/console_helper.rb:9:in `start'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:78:in `console'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/gems/2.2.0/gems/railties-5.0.0/lib/rails/commands.rb:18:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'irb(main):003:0>
I am using rails 5.
I would really appreciate you guys helping me in resolving this error. Thanks in advance
As per your requirement you have defined has_one association between Person and PersonalInfo.
The best way to create PersonalInfo first you should create Person then PersonalInfo such as:
#person = Person.create!(first_name: "Kalman", last_name: "Smith", age: 33, login: "kman", pass: "abc123")
Now you can create PersonalInfo
#person.personal_info.create(height:6.2, weight:220.0)
I think it would help you. Still if you have any concern please let me know.
You'll need to set a person_id:
PersonalInfo.create!(person_id: 1, height:6.2, weight:220.0)
As you can see in your CreatePersonalInfos migration, the person reference has a foreign key constraint. This means you won't be able to create PersonalInfo without an associated Person. You can either create it by providing a valid person_id
PersonalInfo.create!(height:6.2, weight:220.0, person_id:1)
or through the association on Person
#person.create_personal_info(height:6.2, weight:220.0)
You can also remove the foreign_key option in your migration to remove the DB-level constraint.

Stripe Gateway on Active Merchant not working

I was working to make payments through Stripe Gateway through Active Merchant gem on a Rails 4 application.
I came along this script and made a similar script by also watching some other resources as follows:
require 'active_merchant'
# Use the TrustCommerce test servers
ActiveMerchant::Billing::Base.mode = :test
gateway = ActiveMerchant::Billing::StripeGateway.new(:login => Rails.application.secrets.stripe_secret_key)
# ActiveMerchant accepts all amounts as Integer values in cents
amount = 1000 # $10.00
# The card verification value is also known as CVV2, CVC2, or CID
credit_card = ActiveMerchant::Billing::CreditCard.new(
:first_name => 'Bob',
:last_name => 'Bobsen',
:number => '4242424242424242',
:month => '8',
:year => Time.now.year+1,
:verification_value => '000')
purchase_options = {
:ip => "127.0.0.1",
:billing_address => {
:name => "Ryan Bates",
:address1 => "123 Main St.",
:city => "New York",
:state => "NY",
:country => "US",
:zip => "10001"
}
}
# Validating the card automatically detects the card type
if credit_card.validate.empty?
# Capture $10 from the credit card
response = gateway.purchase(amount, credit_card, purchase_options)
if response.success?
puts "Successfully charged $#{sprintf("%.2f", amount / 100)} to the credit card #{credit_card.display_number}"
else
raise StandardError, response.message
end
end
but this script generates an error with the following error log:
/Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:469:in `rescue in api_request': uninitialized constant ActiveMerchant::Billing::StripeGateway::JSON (NameError)
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:463:in `api_request'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:477:in `commit'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:100:in `block (2 levels) in purchase'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:59:in `process'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:98:in `block in purchase'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:45:in `tap'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/response.rb:45:in `run'
from /Library/Ruby/Gems/2.0.0/gems/activemerchant-1.58.0/lib/active_merchant/billing/gateways/stripe.rb:93:in `purchase'
from stripe.rb:35:in `<main>'
Can you suggest a workaround for this error?
I think you just need to add require 'json'. there's no need to add strip to your gemfile
so it looks like a simple workaround as suggested by #bkunzi01
i thought that active merchant already used stripe in its ActiveMerchant::Billing::StripeGateway file but it doesn't.
just included require 'stripe' at the top of the script and transaction was successful :)

Mongoid giving error while saving field with particular name

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>

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.

Rails3, Mongoid, cucumber. Can't set user_id field: illegal ObjectId format

I have an Account model:
class Account
include Mongoid::Document
include Mongoid::Timestamps
referenced_in :user
end
and User:
class User
include Mongoid::Document
include Mongoid::Timestamps
...
references_one :account
...
end
And the following scenario(i try to set reference_one association):
Scenario: Client views his account
Given the following accounts:
| user_id |
| 1123322131 |
.....
And the following step:
Given /^the following accounts:$/ do |class_name, table|
table.hashes.each do |attributes|
Account.create(attributes)
end
end
When I try to run cucumber, I always get an error:
illegal ObjectId format (BSON::InvalidObjectId)
./features/step_definitions/common_steps.rb:7:in `block (2 levels) in <top (required)>'
./features/step_definitions/common_steps.rb:6:in `each'
./features/step_definitions/common_steps.rb:6:in `/^the following accounts:$/'
features/manage_accounts.feature:8:in `And the following accounts:'
full version of backtrace: https://gist.github.com/433ea982d876e1b1fa27
I use: Rails 3.0.3, Ruby 1.9.2, cucumber 1.9.4, machinist 2, mongoid. My Gemfile
What did I do wrong?
UPD. No so obviously behaviour:
> a = Account.create :user_id => "123"
BSON::InvalidObjectId: illegal ObjectId format
> a = Account.create :user_id => 123
=> #<Account _id: 4ceedf055e6f991aef000005, created_at: 2010-11-25 22:11:17 UTC, updated_at: 2010-11-25 22:11:17 UTC, user_id: 123>
> a = Account.create :user_id => "4ceede9b5e6f991aef000007"
=> #<Account _id: 4ceedf1b5e6f991aef000006, created_at: 2010-11-25 22:11:39 UTC, updated_at: 2010-11-25 22:11:39 UTC, user_id: BSON::ObjectId('4ceede9b5e6f991aef000007')>
This could solve your problems:
Given /^the following accounts:$/ do |class_name, table|
table.hashes.each do |attributes|
User.create(attributes).create_account
end
end
Are you using a custom primary key for User? It seems that Mongoid is expecting a normal BSON::ObjectId like BSON::ObjectId('4ceeaf282b2d3a2ab0000001' but you are passing a plain string like 1123322131. In general, you have to be careful when trying to create a record and its associations at the same time

Resources