Cannot modify data with Mongoid - ruby

I can read my database using Mongoid, but cannot write to it.
This example below successfully outputs the activity's device type, but it crashes on the save method with this error message: "undefined method `name' for nil:NilClass"
activity = Activity.find('4d89568d4f21557eb10003fc')
puts activity.deviceType
activity.description = 'my description'
activity.save
Here are my class definitions:
class User
include Mongoid::Document
field :name, :type => String
field :identifier, :type => String
field :email, :type => String
referenced_in :activity
end
class Trackpoint
include Mongoid::Document
field :when, :type => DateTime
field :latitude, :type => Float
field :longitude, :type => Float
field :distance, :type => Float
field :altitude, :type => Float
field :heartRate, :type => Integer
embedded_in :activity, :inverse_of => :trackpoint
end
class Activity
include Mongoid::Document
field :startTime, :type => DateTime
field :description, :type => String
field :sport, :type => String
field :deviceType, :type => String
field :deviceId, :type => String
field :deviceActivityId, :type => String
field :isPublic, :type => Boolean
field :user_id, :type => String
embeds_many :trackpoints
references_one :user
end
Thanks for any help...

Just got rid of the :inverse_of statements and it works now!

Related

Not null fields for ActiveAttr

I'm having issues enforcing a field to not be nil within ActiveAttr::Model.
Is there an elegant way of enforcing this constraint within the model instead of defining it in the controller? Or am I testing incorrectly for the scenario?
Model:
class Message
include ActiveAttr::Model
attribute :name, :presence => true, :allow_nil => false, :allow_blank => false
attribute :email, :presence => true
attribute :content, :presence => true
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
end
RSpec:
module MessageSpecHelper
def valid_message_attributes
{
:name => "Walter White",
:email => "walter#hailtheking.com",
:content => "I am the one who knocks"
}
end
end
it "should have error on name (alternate with nil)" do
#message.attributes = valid_message_attributes.except(:name => nil)
#message.should have(1).error_on(:name)
end

Data-Mapper Under passenger and ruby 1.8

My sinatra app is showing an error when declaring required on fields using datamapper running on passenger and ruby 1.8
error: undefined local variable or method `required' for Person:Class
class Person
include DataMapper::Resource
property :id, Serial
property :salutation, String
property :first_name, String , required => true
property :last_name, String , required => true
property :email, String , required => true, :format => :email_address
property :phone, String , required => true
property :dob, String
property :no_of_guests, String , required => true
property :attending, String, required => true
property :created_at, DateTime
end
Is this an issue with datamapper and ruby 1.8, or passenger or the way I'm decalring the required attribute?
requiredhas to be a symbol (:required):
class Person
include DataMapper::Resource
property :id, Serial
property :salutation, String
property :first_name, String , :required => true
property :last_name, String , :required => true
property :email, String , :required => true, :format => :email_address
property :phone, String , :required => true
property :dob, String
property :no_of_guests, String , :required => true
property :attending, String, :required => true
property :created_at, DateTime
end

Creating a class and adding methods dynamically in Ruby

How do I go about creating a new class and adding a few methods to it without resorting to "eval"?
Here's what I'm trying to do; I'd like to transform this structure:
obj = [
{
:scope => 'account',
:fields => [
{ :title => 'title', :length => 64, :required => true },
{ :title => 'email', :length => 256, :required => true, :type => 'email' }
],
:before_save => Proc.new{
#do something here
},
},
{
:scope => 'product',
:fields => [
{ :title => 'title', :length => 64, :required => true },
{ :title => 'description', :length => 256, :required => true },
{ :title => 'cost', :required => true, :type => 'decimal' }
]
},
]
into this:
class Account
include DataMapper::Resource
property :id, Serial
property :title, String, :length => 64, :required => true
property :email, String, :length => 256, :required => true
def before_save
#do something here
end
end
...
Thanks!
As Andrew already said, there are different ways to create class dynamically. This could be one of them:
Say you start with one DM model (haven't used DM, taking the first one from the docs):
class Post
include DataMapper::Resource
property :id, Serial # An auto-increment integer key
property :title, String # A varchar type string, for short strings
property :body, Text # A text block, for longer string data.
property :created_at, DateTime # A DateTime, for any date you might like.
end
and you want to create it dynamically, from a metadata given in a hash of the form
{:ClassName => {:field1 => :Type1, :field2 => :Type2 ...}}
You could do:
require 'data_mapper'
models = {:Post => {
:id => :Serial,
:title => :String,
:body => :Text
}}
models.each do |name, fields|
klass = Class.new do
include DataMapper::Resource
fields.each do |field_name, field_type|
property(field_name, const_get(field_type))
end
end
Object.const_set(name, klass)
end
Key methods:
Class.new
Module#const_set
If you want to look at a real-world example, please consult the code in this library: https://github.com/apohllo/rod/blob/v0.7.x/lib/rod/model.rb#L410

Mongoid documents inside namespaces

How can I deal with mongoid documents inside namespaces?
I have two mongoid documents as follow:
module A
module B
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User'
end
end
end
The problem raises when I try to delete a group that contains an user:
u = User.create()
g = Group.create()
g.users << u
at this point u.groups_ids contains the _id of the group g, but when I perform:
g.destroy
It complains of a missing method called 'A/B/groups_ids' in class 'User'.
It is trying to remove the reference of g inside u, but it fails to find the correct namespace...
If I remove the namespaces A and B and the :class_name options everything works fine.
Which is the correct way (if any) to handle namespaces in this scenario?
the solution is to add a :foreign_key => 'A/B/groups_ids':
Class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :groups, :cascade => :nullify, :class_name => 'A::B::Group', :foreign_key => 'A/B/group_ids'
end
Class Group
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users, :cascade => :nullify, :class_name => 'A::B::User', :foreign_key => 'A/B/user_ids'
end

How to query Child elements on MongoDB

it's quite looklike with how to query child objects in mongodb
I Have:
Pais (Country) with its children (ufds(27) on total), I'm making a Ruby seed.rb file to bulky insert from a file.
the mapping files are:
class Pais
include Mongoid::Document
field :nome, :type => String
field :sigla, :type => String
embeds_many :ufds
validates_uniqueness_of :sigla
end
class Ufd
include Mongoid::Document
field :codigo_ibge, :type => String
field :sigla, :type => String
field :nome, :type => String
embedded_in :pais, :inverse_of => :ufds
embeds_many :cidades
validates_uniqueness_of :codigo_ibge, :sigla
end
class Cidade
include Mongoid::Document
field :codigo_ibge, :type => String
field :nome, :type => String
embedded_in :ufd, :inverse_of => :cidades
validates_uniqueness_of :codigo_ibge
end
So when importing, I do beside other things the following:
pais_base = Pais.create!(:nome => "Brasil", :sigla => "BR")
File.open(caminho + 'estados.txt').each_with_index do |linha, index|
sigla, nome, ibge = linha.chomp.split("|")
pais_base.ufds << Ufd.new(:sigla => sigla, :nome => nome, :codigo_ibge => ibge )
end
which creates correctly the PAIS and its UFDS children, but now to create a children of UFDS, I load another file and try to find a UFDS with id (codigo_ibge), but always returns null
File.open(caminho + 'cidades.txt').each_with_index do |linha, index|
ufd, ibge, nome = linha.chomp.split("|")
uf = pais_base.ufds.find(:first, :conditions => {:codigo_ibge => ufd.to_s }) <<<<< NIL
uf.cidades << Cidade.new(:codigo_ibge => ibge.to_s, :nome => nome)
end
How should I do that? I've run out of ideas :/
Thanks in advance.
What version of mongoid are you using?
I think your best bet is to use where
This would make your query
uf = pais_base.ufds.where(:codigo_ibge => ufd.to_s }.first
find is only really used when you are looking up an id.

Resources