Ruby - use data of a response as variable - ruby

I'm making a call by this code
require 'riot_api'
# Create Instace of the API
ra = RiotApi::API.new :api_key => 'MY_API', :region => 'na', :debug => true
# Search by Summoner name
summoner_details = ra.summoner.name('GoncyRlz')
And I got this response
#<Hashie::Rash id=31029929 name="GoncyRlz" profile_icon_id=7 revision_date=1375116256000 revision_date_str="07/29/2013 04:44 PM UTC" summoner_level=30>
I want to take that id and save it to a variable called summonerid. How can I take it?

You can just access the id as if it were a method on the object, i.e.
summonerid = summoner_details.id
Also see https://github.com/tcocca/rash

Related

Cannot add new value to MongoDB's BSON field using Ruby

I have a document with the field admins and am looking to add new users into this field. The value for these new users is a simple number string.
def modify_admin(identity, doc)
ip_addr = "127.0.0.1:27017"
client = Mongo::Client.new([ip_addr], :database => "camp")
if doc[0] == 'r'
doc = doc[2..-1]
client[:inventory].update_one({"name": doc}, {$push => {"admins" => identity}})
client.close
end
The collection I'm trying to add is in this line: client[:inventory].update_one({"name": doc}, {$push => {"admins" => identity}}),
However I am running into the error NilClass instances are not allowed as keys in a BSON document. (BSON::InvalidKey).
I have tried different syntax for the $push method but nothing seems to work.
My document structure is as follows, I'm using symbols as the field value.
document = {:name => build_array[1], :owner => identity, :admins => identity}
How can I add new values to the :owner field using Ruby?
$push in ruby usually means global variable. So, all you need is to wrap $push operation into parentheses:
- client[:inventory].update_one({"name": doc}, {$push => {"admins" => identity}})
+ client[:inventory].update_one({"name": doc}, {"$push" => {"admins" => identity}})
And you should be fine

Error with Ruby Google Analytics API

I am trying to use this Ruby Google Analytics API Dashing widget whose Ruby file is
require 'google/api_client'
require 'date'
# Update these to match your own apps credentials
service_account_email = '[YOUR SERVICE ACCOUNT EMAIL]' # Email of service account
key_file = 'path/to/your/keyfile.p12' # File containing your private key
key_secret = 'notasecret' # Password to unlock private key
profileID = '[YOUR PROFILE ID]' # Analytics profile ID.
# Get the Google API client
client = Google::APIClient.new(:application_name => '[YOUR APPLICATION NAME]',
:application_version => '0.01')
# Load your credentials for the service account
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/analytics.readonly',
:issuer => service_account_email,
:signing_key => key)
# Start the scheduler
SCHEDULER.every '1m', :first_in => 0 do
# Request a token for our service account
client.authorization.fetch_access_token!
# Get the analytics API
analytics = client.discovered_api('analytics','v3')
# Start and end dates
startDate = DateTime.now.strftime("%Y-%m-01") # first day of current month
endDate = DateTime.now.strftime("%Y-%m-%d") # now
# Execute the query
visitCount = client.execute(:api_method => analytics.data.ga.get, :parameters => {
'ids' => "ga:" + profileID,
'start-date' => startDate,
'end-date' => endDate,
# 'dimensions' => "ga:month",
'metrics' => "ga:visitors",
# 'sort' => "ga:month"
})
# Update the dashboard
send_event('visitor_count', { current: visitCount.data.rows[0][0] })
end
However I am getting the error Undefined method '[]' for nil:NilClass for the second last line. Can anyone shed some light on what is going on here?
EDIT:
I now know that visitCount.data is an array of NIL objects. Are there any diagnostics I can perform to make sure that that the API is connecting correctly? Can anyone suggest a possible reason why this is happening?
Try this, before streaming the event
if visitCount.data.rows[0].empty?
# assign some default
output = -1
else
output = visitCount.data.rows[0][0]
end
# Update the dashboard
send_event('visitor_count', { current: output })
OK it turns out that I was given the incorrect profile ID. It's kind of surprising that there was no error saying something like "This profile ID does not exist". That would have been way more helpful. Anyways I have the correct profile ID now and it works. In case anyone was wondering, to find the profile ID, you navigate to the analytics profile that you are interested in and the end of the url has something like pXXXXXXXX where the X's are your profile ID.

How to get raw Mongo data results from a MongoMapper Plucky::Query object?

Let's say we have a MongoDB collection called "images", and a MongoMapper-powered application with a corresponding "Image" model. If we set up a MongoMapper query using this model, we see that it is of type Plucky::Query and returns results of type Image:
>> Image.where(:file_type => 'image/jpeg').class
=> Plucky::Query
>> Image.where(:file_type => 'image/jpeg').first.class
=> Image
We can run the corresponding query directly on the Mongo adapter, mostly bypassing MongoMapper, by accessing the MongoMapper.connection. If we do it this way, the query is of type Mongo::Cursor and returns raw data results of type BSON::OrderedHash:
>> MongoMapper.connection.db(dbname).collection('images').find({ :file_type => 'image/jpeg' }).class
=> Mongo::Cursor
>> MongoMapper.connection.db(dbname).collection('images').find({ :file_type => 'image/jpeg' }).first.class
=> BSON::OrderedHash
The question is, is there a way to take a Plucky::Query like above and convert it to (or retrieve from it) a basic, non-extended Mongo::Cursor object?
At first I thought I found a solution with find_each, which does actually take a Plucky::Query and return a Mongo::Cursor:
>> Image.where(:file_type => 'image/jpeg').find_each.class
=> Mongo::Cursor
But it turns out this Mongo::Cursor is somehow extended or otherwise different from the above one because it still returns Image objects instead of BSON::OrderHash objects:
>> Image.where(:file_type => 'image/jpeg').find_each.first.class
=> Image
Update: I can't simply bypass MongoMapper query magic altogether like I did in the second case because I need to access features of MongoMapper (specifically named scopes) to build up the query, so what I end up with is a Plucky::Query. But then I want the results to be plain data objects, not models, because all I need is data and I don't want the overhead of model instantiation.
If you drop to the driver, the transformer is nil by default:
1.9.3p194 :003 > Image.collection.find({ :file_type => 'image/jpeg' }, { :limit => 1 }).first.class
=> BSON::OrderedHash
MongoMapper achieves the conversion by setting a "transformer" lambda on the plucky query. You can see this in the MongoMapper source code:
def query(options={})
query = Plucky::Query.new(collection, :transformer => transformer)
...
end
...
def transformer
#transformer ||= lambda { |doc| load(doc) }
end
So after each mongo document retrieval, this Plucky::Query runs the transformation that loads the model. Looking at the Plucky source code we see that there is a simple setter method [] we can use to disable this. So this is the solution:
plucky_query = Image.where(:file_type => 'image/jpeg')
plucky_query.first.class
# => Image
plucky_query[:transformer] = nil
plucky_query.first.class
# => BSON::OrderedHash
If you don't mind monkey-patching you can encapsulate like so:
module Plucky
class Query
def raw_data
self[:transformer] = nil
self
end
end
end
Then you could simply write:
Image.where(:file_type => 'image/jpeg').raw_data.first.class
# => BSON::OrderedHash

Get values from server response in ruby

I send request to server and server returns me response. If I print this response, it looks exactly as mentioned below (with array and braces). I'm new to Ruby so I have two questions:
1. To what structure should I add this response?
2. How to I get values from this response (eg value of user_id or user_status). How to get rid of quotes in value
Request code:
def userGet(user_id_or_email)
uri = URI(SRV + '/userGet')
http = Net::HTTP.new(uri.host,uri.port)
req = Net::HTTP::Post.new(uri.path)
req['bla-bla'] = 'bla-bla'
req.set_form_data('search' => user_id_or_email)
res = http.request(req)
puts(res.read_body)
end
Output of puts(res)
array (
'user_id' => 301877459,
'login' => '0301877459',
'email' => 'YS5raG96eWFfdHZhc2lsaWlAY29ycC5iYWRvby5jb20=',
'passwd' => 'cc03e747a6afbbcbf8be7668acfebee5',
'partner_id' => '105',
'user_status' => 'active',
'nickname' => 'Test',
'fullname' => 'Test',
)
As other commentors have mentioned, the first step is to determine the encoding of the response. If you can easily change the way that the data is returned by the server, you could output valid JSON and use a gem such as this. If you cannot, then an ad-hoc method for parsing responses of this type would be to define a function like this:
def parseResult(res)
# Remove the array wrapper and any leading/trailing whitespace
parsed_string = res.gsub(/^\s*array\s*\(/, "").gsub(/[\s,]*\)[\s,]*$/, "")
# Split the string into an array of key-value tuples
parsed_array = parsed_string.split(',').collect do |tuple|
tuple.split("=>").collect do |x|
x.match(/^[\s',]*([^',]*)[\s',]*$/)[1]
end
end
# Convert the array of tuples into a hash for easy access
Hash[parsed_array]
end
This is similar sawa's method, but it assumes that you cannot trust the data being returned by the server and therefore cannot use eval safely.
Not sure what that array ( ... ) means, but assuming it means a hash, you can do:
string.eval(
string
.sub(/\A\s*array\s*\(/, "{")
.sub(/\)\s*\z/, "}")
)

How to keep Ruby object instance variables hidden from view in irb or logs?

I am making a gem to wrap an API. The service requires a few login parameters so I made a Connection class to initialize by passing in all login values, and storing with instance variables. One of these values, #secret_access_key is secret, obviously. It is not readable within the app. But while testing the gem in irb, I see the secret key displayed along with all other instance variables when the object is returned.
mws = MWS::Connection.new :access_key => '1', :secret_access_key => 'SECRET!!!', :merchant_id => '3', :marketplace_id => '4'
=> #<MWS::Connection:0x007fbd22acef40 #access_key="1", #merchant_id="3", #marketplace_id="4", #secret_access_key="SECRET!!!">
I am paranoid that the secret key will show up in Heroku logs, app error messages, or whatever else.
Should I be worrying? If so, what's the best way to store or hide this information?
Also, I am using httparty gem to manage this, is there something better I can do with that gem?
You could use this workaround:
class MWS::Connection
def inspect
"#<MWS::Connection:#{object_id}>"
end
end
Of course the secret key will still be accessible, but it shouldn't show up in any logs now:
mws = MWS::Connection.new :access_key => '1', :secret_access_key => 'SECRET!!!', :merchant_id => '3', :marketplace_id => '4'
# => #<MWS::Connection:0x007fbd22acef40>
mws.instance_variable_get(:#secret_access_key) # => 'SECRET!!!'
class MWS::Connection
def initalize(opts)
...
#secret_access_key = Cypher.encypher(opts[:secret_access_key]) if opts[:secret_access_key]
end
def secret_access_key
Cypher.decypher #secret_access_key
end
end
class Cypher
def self.encypher(str)
str + 'fancy_encryption_protocol'
end
def self.decypher(str)
str.sub 'fancy_encryption_protocol$', ''
end
end

Resources