How to query Child elements on MongoDB - ruby

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.

Related

How do I reference the same Carrierwave uploaded file in multiple Ruby model instances without reprocessing

I have a model that is using Carrierwave as an uploader to upload files to fog storage.
The problem is that when I create say 100 model objects they all upload the same file.
I need the model instances to reference the same uploaded file. A one-to-many relationship where there are many model instances and 1 file.
At the moment the file is an attribute called attachment on my model messages.rb -
class Message < ActiveRecord::Base
attr_accessible :body, :remote_attachment_url, :from, :to, :status, :attachment, :campaign, :version, :user_id, :SmsId, :response, :response_code, :client_id
mount_uploader :attachment, AttachmentUploader
end
I set attachment in my controller when I create a new Message instance in MessagesController.rb -
recipients.each do |value|
#message = Message.new(:attachment => params[:message][:attachment], :campaign => message[:campaign], :version => message[:version], :to => value, :body => body, :status => status, :user_id => current_user.id, :client_id => client.id )
end
I'm using Ruby 2.0, Rails 4
Solution:
I fixed this by pushing my attachment file into a new model then building an association between the message object and the attachment object.
MessagesController:
#attachment = Attachment.create(params[:message][:attachment_attributes])
recipients.each do |value|
#message = Message.new(:campaign => params[:message][:campaign], :version => params[:message][:version], :to => value, :body => params[:message][:body], :status => status, :user_id => current_user.id, :client_id => client.id )
#message.attachment = #attachment
end
Message model:
attr_accessible :attachment_id, :attachment_attributes
belongs_to :attachment
accepts_nested_attributes_for :attachment
Attachment model:
attr_accessible :attached, :remote_attached_url, :attachment_attributes
mount_uploader :attached, AttachmentUploader
If in your model that mounts the carrierwave uploader you have a property:
mount_uploader :attachment, YourUploader
so assuming your new object is created, you should be able to assign the image like this:
newObj.attachment = anotherObj.attachment
newObj.save
Let me know if that works.

Why is one of my tables not being populated if I use DataMapper's "has n" and "belongs_to" methods?

I am getting to grips with DataMapper on sqlite3 at the moment. I have to models defined which are creating two tables: "companies" and "apps".
Each app belongs to a company and each company many apps. I want to represent this relationship in my models but I add the "has n" and "belongs_to" methods to each class, the App class stops working when call #create on a bunch of apps, they are not inserted into the database.
If I don't have the associations methods then everything works fine.
This is my DataMapper code:
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")
class Company
include DataMapper::Resource
property :id, Serial
property :company_name,
property :company_id, Text, :unique => true
has n, :apps
end
class App
include DataMapper::Resource
property :id, Serial
property :app_id, Integer
property :bundle_id, Text
property :game_name, Text
property :company_name, Text
property :created_at, DateTime
property :rank, Integer
belongs_to :company
end
DataMapper.finalize.auto_upgrade!
puts 'Database and tables created'
This is the code I am using to populate my tables
companies_in_chart.each do |company|
#add_company = Company.create(
:company_name => company["company_name"],
:company_id => company["company_id"]
)
end
puts "Inserted companies into database"
apps_arr.each do |app|
#new_app = App.create(
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_name => app["company_name"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted apps into database"
EDIT: New code
#Set up database and apps table
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/app.db")
class Company
include DataMapper::Resource
property :id, Serial
property :company_name, Text, :required => true, :lazy => false
property :company_id, Text, :required => true, :lazy => false, :unique => true
has n, :apps
end
class App
include DataMapper::Resource
property :id, Serial
property :app_id, Integer, :required => true
property :bundle_id, Text, :required => true, :lazy => false
property :game_name, Text, :required => true, :lazy => false
property :company_id, Text, :required => true, :lazy => false
property :created_at, DateTime
property :rank, Integer
belongs_to :company
end
DataMapper.finalize.auto_upgrade!
puts 'Database and tables created'
#Insert apps and companies into database
apps_arr.each do |app|
# Creates a new company based on app entry if the company does
# not exist in the companies table
#add_company = Company.create(
:company_name => app["company_name"],
:company_id => app["company_id"]
)
#add_app = App.create(
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_id => app["company_id"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted app and companies into database"
#company = Company.first
ap #company # => #<Company #id=1 #company_name="Rovio Entertainment Ltd" #company_id="rovio">
ap #company.apps # => [] --I was hoping it would return all of Rovio's apps in the database
apps not created cause you have to attach a company when creating app.
if you want to add apps not attached to any company, use this in you App model:
belongs_to :company, :required => false
to attach a company when creating app:
#Insert apps and companies into database
apps_arr.each do |app|
# Creates a new company based on app entry if the company does
# not exist in the companies table
company = Company.first_or_create(
:company_name => app["company_name"],
:company_id => app["company_id"]
)
app = App.first_or_create(
:company => company, # you missed this
:app_id => app["app_id"],
:bundle_id => app["bundle_id"],
:game_name => app["game_name"],
:company_id => app["company_id"],
:created_at => app["DateTime"],
:rank => app["rank"]
)
end
puts "Inserted app and companies into database"
I successfully replicated your code on CIBox and it runs perfectly.
See the code and live demo here
As you can see, it creates a company and attach it to created app.
Company.first.apps returns created app, so associations works correctly.

How do I fetch multiple hash keys with a nested hash?

I'm playing around with nested hashes and I'm trying to figure out how to fetch multiple keys when my hash is a nested one:
imahash = { :id => { :name => "Alma", :email => "alma#mail.com" },
:stats => { :gender => "Female" },
:location => { :city => "Freeport", :state => "Maine" }
}
I know how to retrieve the nested value, and typing in the hash name will dump all the keys and values. But what I want to do is to fetch specific keys, such as :name and :gender only. Or :name and :city only.
Is this possible? Because from what I've found, it seems that you can only retrieve hash values for one key at a time or for all the keys at once.
My desired output would be something like:
=> { :id => { :name => "Alma" }, :location => { :city => "Freeport" } }
I presume you want to grab the values out in a tuple? You can make an array that contains whatever collection of values you want.
Try the following for name and city:
[imahash[:id][:name], imahash[:location][:city]]
=> ["Alma", "Freeport"]
Not exactly sure what you're asking here, but it seems like you're wanting to create a new hash from the bigger one.
To fetch specific keys like :name and :gender only
name_and_gender_hash = {
:name => imahash[:id][:name],
:gender => imahash[:stats][:gender]
}
would result in
{:name => "Alma", :gender => "female"}

Cannot modify data with Mongoid

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!

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

Resources