ruby mongoDB insert_many - success message but no inserts - ruby-on-rails

I'm trying to do insert_many using Ruby Driver of MongoDB but it's not working. Any help would be appreciated.
Here's my sample model:
class User
include Mongoid::Document
include Mongoid::Timestamps
field :message
end
MongoDB Rails code:
client = Mongo::Client.new('mongodb://127.0.0.1:27017/development')
collection = client[:user]
u = Hash.new
u['message'] = 'hi'
documents = []
documents << u
result = collection.insert_many(documents)
#<Mongo::BulkWrite::Result:0x00007fa6ed4e99b8 #results={"n_inserted"=>1, "n"=>1, "inserted_ids"=>[BSON::ObjectId('5e9ac4c6c40dc6a955465a8f')]}>
When I verify the insert, it seems to work, but when I query the model, there's no data:
result
#<Mongo::BulkWrite::Result:0x00007fa6ed4e99b8 #results={"n_inserted"=>1, "n"=>1, "inserted_ids"=>[BSON::ObjectId('5e9ac4c6c40dc6a955465a8f')]}>
User.count
0
Any suggestions?

I finally figured out the issue. It's the collection itself. All I need to do is this to get the collection, then I can apply MongDB Ruby Driver methods:
user_collection = User.collection

Related

attr_accessor not updating value from rails model

I have the following model
class Job < ActiveRecord::Base
attr_accessor :incentive
end
I want to be able to store a temporary column in my model via attr_accessor.
I want to be able to do something like this
job = Job.last
job.incentive = {id: 1}
and i expect if i do job.incentive, it should return {id: 1}
I also tried doing this as well
def incentive =(val)
#incentive = val
end
def incentive
#incentive
end
But that also didn't work. How can i be able to store temporary column values in rails 4
You script is fine, you'll find the below script working perfectly in your rails console:
job = Job.last
job.incentive = { id: 1 }
p job.incentive # returns { id: 1 }
If you restart or refresh your console (or webpage) this information is gone, since it is only set in memory and not stored to the database.

Rails Httparty JSON to params to save

Rails 4.5 Ruby 2.3.1
I am getting json from an API and trying to store the following into a model CLrates
1. timestamp as unix time (date)
2. Currency_code (string)
3. quote (decimal monetary value)
I can use the following in irb after parsing the json and know how to get the elements individually using: response["quotes"]. How can I generate params to be saved in the model above when the body is as follows:
irb(main):036:0> puts response.body
{
"success":true,
"terms":"https:\/\/xxxxx.com\/terms",
"privacy":"https:\/\/xxxxx.com\/privacy",
"timestamp":1504817289,
"source":"USD",
"quotes":{
"USDAED":3.672703,
"USDAFN":68.360001,
"USDCUC":1,
"USDCUP":26.5,
"USDCVE":91.699997,
"USDCZK":21.718701,
............ many more lines removed for brevity
"USDZWL":322.355011
}
I can do this using a separate associated model but have very little idea how to create the params to save to a single table.
The following links got me to this point and well worth a read if you need info on httparty GET (client):
1. http://www.rubydoc.info/github/jnunemaker/httparty/HTTParty/
2. http://eric-price.net/blog/rails-api-wrapper/
3. https://www.driftingruby.com/episodes/playing-with-json
The class and method in lib/clayer.rb:
class clayer
include HTTParty
format :json
read_timeout 10
def self.get_quotes
response = HTTParty.get('http://www.nnnnnnn.net/api/live?
access_key=nnnnnnnnnn&format=1')
end
end
I used irb as I am still learning how to run this through rails c. This will be called in the controller and saved however need to work out how to get the params from the json
Thanks for the help
OK: after digging I think I am on the right track
I get the response["QUOTES"], loop through them and build the params required saving each at the end of the loop
rates = response["QUOTES"]
rates.each do |k,v|
clrate = Realtimerates.new
clrate.date = response["timestamp"]
clrate.countrycode = "#{k}"
clrate.price = "#{v}"
clrate.save
end
Going to give this a whirl
In model
class Realtimerate < ActiveRecord::Base
include HTTParty
format :json
read_timeout 5
def self.get_cl_rates
response = HTTParty.get('http://www.mmmmm.net/api/live?access_key="key"&format=1')
rates = response["quotes"]
rates.each do |k,v|
create!(
date: Time.at(response["timestamp"]),
country_code: "#{k}",
price: "#{v}")
end
end
end
In the controller:
def index
Realtimerate.get_cl_rates
#realtimerates = Realtimerate.all
end
This is working and shows latest GET.
You already have a hash in your response.body. All you need to do now is to assign the relevant key-value to your model's attributes. e.g.
clrate = ClRate.new
res = response.body
clate.time = res["timestamp"]
...
clate.save

Rails Eager loading has_many associations for an existing object

I am fairly new to rails & I am having this performance issue that I would appreciate any help with.
I have a User model & each user has_many UserScores associated. I am preparing a dashboard showing different user stats including counts of user_scores based on certain conditions. Here is a snippet of the code:
def dashboard
#users = Array.new
users = User.order('created_at ASC')
users.each do |u|
user = {}
user[:id] = u.id
user[:name] = u.nickname
user[:email] = u.email
user[:matches] = u.user_scores.count
user[:jokers_used] = u.user_scores.where(:joker => true).length
user[:jokers] = u.joker
user[:bonus] = u.user_scores.where(:bonus => 1).length
user[:joined] = u.created_at.strftime("%y/%m/%d")
if user[:matches] > 0
user[:last_activity] = u.user_scores.order('updated_at DESC').first.updated_at.strftime("%y/%m/%d")
else
user[:last_activity] = u.updated_at.strftime("%y/%m/%d")
end
#users << user
end
#user_count = #users.count
end
The issue I am seeing is repeated UserScore db queries for each user to get the different counts.
Is there a way to avoid those multiple queries??
N.B. I'm not sure if my approach for preparing data for the view is the optimal way, so any advice or tips regarding that will be greatly appreciated as well.
Thanks
You need to eager load users_scores to reduce multiple queries. #Slava.K provided good explanation on how to eliminate that.
Add includes(:user_scores) for querying users, and use ruby's methods to work with collections once data is fetched from DB through query.
See code below to understand that:
users = User.includes(:user_scores).order('created_at ASC')
users.each do |u|
....
user[:matches] = u.user_scores.length
user[:jokers_used] = u.user_scopes.select{ |score| score.joker == true }.length
user[:jokers] = u.joker
user[:bonus] = u.user_scores.select{ |score| score.bonus == 1 }.length
....
end
Also, The way you are preparing response is not clean and flexible. Instead you should override as_json method to prepare json which can consumed by views properly. as_json method is defined for models by default. You can read more about it from official documentation http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html or visit article on preparing clean json response where I explained about overriding as_json properly in-depth.
Use includes method for eager loading your has many associations. You can understand this concept here: https://www.youtube.com/watch?v=s2EPVMqOsTQ
Firstly, reference user_scores association in your query:
users = User.includes(:user_scores).order('created_at ASC')
Follow rails documentation associations eager loading: http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
Also note that where makes new query to the database even if your association is already preloaded. Therefore, instead of
u.user_scores.where(:joker => true).length
u.user_scores.where(:bonus => 1).length
try:
u.user_scores.count { |us| us.joker }
u.user_scores.count { |us| us.bonus == 1 }
You will probably have to rewrite .user_scores.order('updated_at DESC').first.updated_at.strftime("%y/%m/%d") somehow as well

Ruby class attributes not querying correctly

I have a class in my Ruby on Rails project for Institutions that I recently had to add an attribute to, an :identifier. The class has a custom metadata field that accompanies it for searching and indexing purposes. The problem is, the new attribute I added isn't helping me find objects the way I wanted. If I try to query for an object using the :identifier to do so I get consistently get an empty array. And yes, I have checked multiple times to ensure that the test object actually exists.
This is the model:
class Institution < ActiveFedora::Base
include Hydra::AccessControls::Permissions
# NOTE with rdf datastreams must query like so ins = Institution.where(desc_metadata__name_tesim: "APTrust")
has_metadata "rightsMetadata", type: Hydra::Datastream::RightsMetadata
has_metadata 'descMetadata', type: InstitutionMetadata
has_many :intellectual_objects, property: :is_part_of
has_attributes :name, :brief_name, :identifier, datastream: 'descMetadata', multiple: false
validates :name, :identifier, presence: true
validate :name_is_unique
validate :identifier_is_unique
def users
User.where(institution_pid: self.pid).to_a.sort_by(&:name)
end
private
def name_is_unique
errors.add(:name, "has already been taken") if Institution.where(desc_metadata__name_ssim: self.name).reject{|r| r == self}.any?
end
def identifier_is_unique
count = 0;
Institution.all.each do |inst|
count += 1 if inst.identifier == self.identifier
end
if(count > 0)
errors.add(:identifier, "has already been taken")
end
#errors.add(:identifier, "has already been taken") if Institution.where(desc_metadata__identifier_ssim: self.identifier).reject{|r| r.identifier == self.identifier}.any?
end
end
As you can see, I had to write a very different method to check for the uniqueness of an identifier because the .where method wasn't returning anything. I didn't realize that was the problem though until I started working on the show model in the controller (below):
def show
identifier = params[:identifier] << "." << params[:format]
#institution = Institution.where(desc_metadata__identifier_ssim: identifier)
end
This never returns anything even though I have several Institution objects in my database and have double and triple checked that the URL parameters are correct. And part of double checking that was searching for objects in the console. Here's the output:
Loading development environment (Rails 4.0.3)
2.0.0-p353 :001 > ap = Institution.where(desc_metadata__name_ssim: "APTrust")
ActiveFedora: loading fedora config from /Users/kec6en/HydraApp/fluctus/config/fedora.yml
ActiveFedora: loading solr config from /Users/kec6en/HydraApp/fluctus/config/solr.yml
Loaded datastream list for aptrust-dev:379 (3.2ms)
Loaded datastream profile aptrust-dev:379/RELS-EXT (2.7ms)
Loaded datastream content aptrust-dev:379/RELS-EXT (2.4ms)
Loaded datastream profile aptrust-dev:379/descMetadata (2.6ms)
Loaded datastream profile aptrust-dev:379/descMetadata (3.5ms)
Loaded datastream content aptrust-dev:379/descMetadata (3.1ms)
=> [#<Institution pid: "aptrust-dev:379", name: "APTrust", brief_name: "apt", identifier: "aptrust.org">]
2.0.0-p353 :002 > apt = Institution.where(desc_metadata__identifier_ssim: "aptrust.org")
=> []
2.0.0-p353 :003 >
As you can see, I'm querying for an identifier that does exist but it's not finding anything. For reference, here is the metadata datastream that I'm working off of. Note that the identifier is indexed as :stored_searchable so I should be able to query for it.
class InstitutionMetadata < ActiveFedora::RdfxmlRDFDatastream
map_predicates do |map|
map.name(in: RDF::DC, to: 'title') { |index| index.as :symbol, :stored_searchable }
map.brief_name(in: RDF::DC, to: 'alternative')
map.identifier(in: RDF::DC, to: 'identifier') { |index| index.as :symbol, :stored_searchable }
end
end
I modeled it after the name attribute because that one appears to be working. Any ideas why the identifier isn't?
Thanks!
Why don't you just search the identifier directly instead of using the desc_metadata?
Institution.where identifier: "aptrust.org"
Using desc_metadata__identifier_tesim instead of desc_metadata__identifier_ssim seems to work for finding objects, although it still doesn't work for the uniquess checking method I wrote.

How can I hide a column from a model in Rails 3.2?

Prior to Rails 3.1, we could update the self.columns method of ActiveRecord::Base.
But that doesn't seem to work now.
Now it seems if I remove a column from a table, I am forced to restart the Rails server. If I don't I keep getting errors when INSERTs to the table happen. Rails still thinks the old column exists, even though it's not in the database anymore.
Active Record does not support this out of the box, because it queries the database to get the columns of a model (unlike Merb's ORM tool, Datamapper).
Nonetheless, you can patch this feature on Rails with (assuming, for instance, you want to ignore columns starting with "deprecated" string):
module ActiveRecord
module ConnectionAdapters
class SchemaCache
def initialize(conn)
#connection = conn
#tables = {}
#columns = Hash.new do |h, table_name|
columns = conn.columns(table_name, "#{table_name} Columns").reject { |c| c.name.start_with? "deprecated"}
h[table_name] = columns
end
#columns_hash = Hash.new do |h, table_name|
h[table_name] = Hash[columns[table_name].map { |col|
[col.name, col]
}]
end
#primary_keys = Hash.new do |h, table_name|
h[table_name] = table_exists?(table_name) ? conn.primary_key(table_name) : nil
end
end
end
end
end
You can clear the ActiveRecord schema cache:
ActiveRecord::Base.connection.schema_cache.clear_table_cache(:table_name)!
Then it'll be reloaded the next time you reference a model that uses that table.

Resources