For convention reasons I would like to initialize the Fitgem client in config/initializers/fitgem.rb. When I say initialize I mean pass in my app's consumer token and consumer secret like so:
Fitgem.configure do |config|
config.consumer_key = "XXXX"
config.consumer_secret = "XXXX"
config.token = "XXXX"
config.secret = "XXXX"
end
This is the exact same manner that is done with Facebook and Twitter clients (https://github.com/sferik/twitter) elsewhere. Is there a similar way I can do this with Fitgem?
The error I receive when I try to initialize the client this way is:
undefined method `configure' for Fitgem:Module
The fitgem docs (http://www.rubydoc.info/github/whazzmaster/fitgem/frames) say to do it like this:
client = Fitgem::Client.new {
:consumer_key => my_key,
:consumer_secret => my_secret,
:token => fitbit_oauth_token,
:secret => fitbit_oauth_secret
}
But I don't want to have to re-initialize the Fitgem client in every method.
So, number 1, I would love to know how to do this, and number 2 I would love to know how to look at the fitgem code to see that configure is not an acceptable method.
Maybe it's been out of date to answer, but now there is omniouth for fitbit. It's not so difficult to use the gem because there is the explanation about how to do the configuration. You have to make omniauth.rb file under config/initializers and place the consumer_key and consumer_secret there.
Related
I am trying to get the bandwidth data for all the softlayer servers under my account.
Thanks to account_servers.rb I am able to get the server id for all the servers. Now I would like to get the Bandwidth used by the servers for a particular time frame. The data that I am interested is
http://sldn.softlayer.com/reference/datatypes/SoftLayer_Metric_Tracking_Object_Bandwidth_Summary
.
I tried to get information using softlayer_client.service_named("Metric_Tracking_Object_Bandwidth_Summary"). Unfortunately I am not able to get the details.
I did find a java code, but I am interested in ruby code. Can someone please guide me to get the server bandwith summary?
Getting bandWidth data in SL
Please, try the following Ruby examples:
require 'rubygems'
require 'softlayer_api'
server_id = 11498369
# Your SoftLayer API username.
SL_API_USERNAME = 'set me'
# Your SoftLayer API key.
SL_API_KEY = 'set me'
softlayer_client = SoftLayer::Client.new(:username => SL_API_USERNAME,
:api_key => SL_API_KEY)
vsi_service = softlayer_client.service_named('SoftLayer_Virtual_Guest')
metric_tracking_object_id = vsi_service.object_with_id(server_id).getMetricTrackingObjectId
metric_service = softlayer_client.service_named('SoftLayer_Metric_Tracking_Object')
service_ref = metric_service.object_with_id(metric_tracking_object_id)
begin
object_template = [{
'keyName' => 'PUBLICOUT',
'summaryType' => 'sum'
}]
result = service_ref.getSummaryData('2016-03-29T00:00:00','2016-03-30T00:00:00',object_template,600)
puts result.inspect
rescue => e
puts 'Error when executing the script...'
$stdout.print(e.inspect)
end
References:
SoftLayer_Metric_Tracking_Object::getSummaryData
SoftLayer_Virtual_Guest::getMetricTrackingObjectId
Second example using SoftLayer_Virtual_Gues::getBandwidthDataByDate:
require 'rubygems'
require 'softlayer_api'
require 'pp'
require 'date'
# Set the server id that you wish to get Bandwidth information.
server_id = 11498369
softlayer_client = SoftLayer::Client.new(:username => 'set me',
:api_key => 'set me')
server = SoftLayer::VirtualServer.server_with_id(server_id, :client => softlayer_client)
get_bandwidth_data_by_date = server.service.getBandwidthDataByDate('2016-03-29T00:00:00','2016-03-30T00:00:00','public')
pp('getBandwidthDataByDate: ', get_bandwidth_data_by_date)
References:
SoftLayer_Virtual_Guest::getBandwidthDataByDate
Disclamer: I created my own Ruby SoftLayer client, you can check it at http://github.com/zertico/softlayer specially for situations like this one where you want to access some specific data (and I'm not SoftLayer staff ;) )
If you'd like to give it a try the code that solves your problem is
ps: I'm considering you are manipulating a SoftLayer_Hardware_Server, right?
hardware = Softlayer::Hardware::Server.find(123)
hardware.get_current_bandwidth_summary
mask = 'mask[currentBandwidthSummary]'
hardware = Softlayer::Hardware::Server.mask(mask).find(123)
hardware.current_bandwidth_summary
You will access a ruby object like this one:
=> #<Softlayer::Metric::Tracking::Object::Bandwidth::Summary:0x007ff74b683540
#allocation_amount="1234",
#allocation_id=111111,
#amount_out="12.34567",
#average_daily_usage="1.23",
#currently_over_allocation_flag=0,
#id=1111111,
#outbound_bandwidth_amount="123.45678",
#projected_bandwidth_usage="123.45",
#projected_over_allocation_flag=0>
Hope it can helps you, comment if you have any doubt about the client usage
I have set up a dashboard using dashing with a number of (mostly) existing widgets. That worked so far - see production dashboard here (work in progress).
Now I would like to have an Instagram widget that displays the n lastest images taken by username.
I have found a widget that will display images by long and lat and also was able to get my tokens configured, so I can talk to the Instagram API.
Here's the code of my current widget originally from #mjamieson's gist on github.
require 'instagram'
require 'rest-client'
require 'json'
# Instagram Client ID from http://instagram.com/developer
Instagram.configure do |config|
config.client_id = ENV['INSTAGRAM_CLIENT_ID']
config.client_secret = ENV['INSTAGRAM_CLIENT_SECRET']
end
# Latitude, Longitude for location
instadash_location_lat = '45.429522'
instadash_location_long = '-75.689613'
SCHEDULER.every '10m', :first_in => 0 do |job|
photos = Instagram.media_search(instadash_location_lat,instadash_location_long)
if photos
photos.map do |photo|
{ photo: "#{photo.images.low_resolution.url}" }
end
end
send_event('instadash', photos: photos)
end
I got this to work, but would like to modify the given API call to only display images taken by me / a user of my choice. Unfortunately I don't understand ruby or json enough to figure out what the Instagram API documentation wants me to do.
I found the following url
https://api.instagram.com/v1/users/{user-id}/media/recent/?access_token={acces-token}
and tried it (with my credentials filled in). It returned json data correctly including my images (among other data).
How can I modify the given code to display images by username instead of location?
Any help is greatly appreciated.
You'll need an access_token to get content from some user. Take a look at sample application on gem page.
It seems you need something like this:
# here we take access token from session, assuming you already got it
# sometime before and stored it there for future use
client = Instagram.client(:access_token => session[:access_token])
photos = client.user_recent_media
And this example how to get this access_token using OAuth2 browser authorization and sinatra app:
require "sinatra"
require "instagram"
enable :sessions
CALLBACK_URL = "http://localhost:4567/oauth/callback"
Instagram.configure do |config|
config.client_id = "YOUR_CLIENT_ID"
config.client_secret = "YOUR_CLIENT_SECRET"
# For secured endpoints only
#config.client_ips = '<Comma separated list of IPs>'
end
get "/" do
'Connect with Instagram'
end
get "/oauth/connect" do
redirect Instagram.authorize_url(:redirect_uri => CALLBACK_URL)
end
get "/oauth/callback" do
response = Instagram.get_access_token(params[:code], :redirect_uri => CALLBACK_URL)
session[:access_token] = response.access_token
redirect "/nav"
end
Solution
require 'sinatra'
require 'instagram'
# Instagram Client ID from http://instagram.com/developer
Instagram.configure do |config|
config.client_id = ENV['INSTAGRAM_CLIENT_ID']
config.client_secret = ENV['INSTAGRAM_CLIENT_SECRET']
config.access_token = ENV['INSTAGRAM_ACCESS_TOKEN']
end
user_id = ENV['INSTAGRAM_USER_ID']
SCHEDULER.every '2m', :first_in => 0 do |job|
photos = Instagram.user_recent_media("#{user_id}")
if photos
photos.map! do |photo|
{ photo: "#{photo.images.low_resolution.url}" }
end
end
send_event('instadash', photos: photos)
end
Explaination
1.) In addition to the client_id and client_secret I had defined before, I just needed to add my access_token to the Instagram.configure section.
2.) The SCHEDULER was correctly working, but needed to call Instagram.user_recent_media("#{user_id}") instead of Instagram.media_search(instadash_location_lat,instadash_location_long)
3.) To do that I had to set a second missing variable for user_id
Now the call gets recent media filtered by user ID and outputs it into the dashing widget.
Thanks for the participation and hints! That pointed me into the right direction of the documentation and helped me to figure it out myself.
I have been tasked with creating a Ruby API that retrieves youtube URL's. However, I am not sure of the proper way to create an 'API'... I did the following code below as a Sinatra server that serves up JSON, but what exactly would be the definition of an API and would this qualify as one? If this is not an API, how can I make in an API? Thanks in advance.
require 'open-uri'
require 'json'
require 'sinatra'
# get user input
puts "Please enter a search (seperate words by commas):"
search_input = gets.chomp
puts
puts "Performing search on YOUTUBE ... go to '/videos' API endpoint to see the results and use the output"
puts
# define query parameters
api_key = 'my_key_here'
search_url = 'https://www.googleapis.com/youtube/v3/search'
params = {
part: 'snippet',
q: search_input,
type: 'video',
videoCaption: 'closedCaption',
key: api_key
}
# use search_url and query parameters to construct a url, then open and parse the result
uri = URI.parse(search_url)
uri.query = URI.encode_www_form(params)
result = JSON.parse(open(uri).read)
# class to define attributes of each video and format into eventual json
class Video
attr_accessor :title, :description, :url
def initialize
#title = nil
#description = nil
#url = nil
end
def to_hash
{
'title' => #title,
'description' => #description,
'url' => #url
}
end
def to_json
self.to_hash.to_json
end
end
# create an array with top 3 search results
results_array = []
result["items"].take(3).each do |video|
#video = Video.new
#video.title = video["snippet"]["title"]
#video.description = video["snippet"]["description"]
#video.url = video["snippet"]["thumbnails"]["default"]["url"]
results_array << #video.to_json.gsub!(/\"/, '\'')
end
# define the API endpoint
get '/videos' do
results_array.to_json
end
An "API = Application Program Interface" is, simply, something that another program can reliably use to get a job done, without having to busy its little head about exactly how the job is done.
Perhaps the simplest thing to do now, if possible, is to go back to the person who "tasked" you with this task, and to ask him/her, "well, what do you have in mind?" The best API that you can design, in this case, will be the one that is most convenient for the people (who are writing the programs which ...) will actually have to use it. "Don't guess. Ask!"
A very common strategy for an API, in a language like Ruby, is to define a class which represents "this application's connection to this service." Anyone who wants to use the API does so by calling some function which will return a new instance of this class. Thereafter, the program uses this object to issue and handle requests.
The requests, also, are objects. To issue a request, you first ask the API-connection object to give you a new request-object. You then fill-out the request with whatever particulars, then tell the request object to "go!" At some point in the future, and by some appropriate means (such as a callback ...) the request-object informs you that it succeeded or that it failed.
"A whole lot of voodoo-magic might have taken place," between the request object and the connection object which spawned it, but the client does not have to care. And that, most of all, is the objective of any API. "It Just Works.™"
I think they want you to create a third-party library. Imagine you are schizophrenic for a while.
Joe wants to build a Sinatra application to list some YouTube videos, but he is lazy and he does not want to do the dirty work, he just wants to drop something in, give it some credentials, ask for urls and use them, finito.
Joe asks Bob to implement it for him and he gives him his requirements: "Bob, I need YouTube library. I need it to do:"
# Please note that I don't know how YouTube API works, just guessing.
client = YouTube.new(api_key: 'hola')
video_urls = client.videos # => ['https://...', 'https://...', ...]
And Bob says "OK." end spends a day in his interactive console.
So first, you should figure out how you are going to use your not-yet-existing lib, if you can – sometimes you just don't know yet.
Next, build that library based on the requirements, then drop it in your Sinatra app and you're done. Does that help?
I want to use the ruby gem 'twitter' but for an unknown reason it does not work.
Here's the error I get when running the script:
C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/faraday-0.8.6/lib/faraday/reques/multipart.rb:5 warning: already initialized constant DEFAULT_BOUNDARY
Twitter::Error::ClientError: initialize: name or service not known
request at C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/twitter-4.5.0/lib/twitter/client.rb:85
get at C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/twitter-4.5.0/lib/twitter/client.rb:64
__send__ at org/jruby/RubyBasicObject.java:1671
send at org/jruby/RubyKernel.java:2094
cursor_from_response at C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/twitter-4.5.0/lib/twitter/api/utils.rb:108
cursor_from_response_with_user at C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/twitter-4.5.0/lib/twitter/api/utils.rb:96
friends at C:/nwcloud/jruby-1.7.2/lib/ruby/gems/shared/gems/twitter-4.5.0/lib/twitter/api/friends_and_followers.rb:314
(root) at tCon.rb:11
I registered my application in my twitter developer account and installed the gem.
Here's my coding (I removed all keys):
require 'twitter'
client = Twitter::Client.new(
:consumer_key => "",
:consumer_secret => "",
:oauth_token => "",
:oauth_token_secret => ""
)
client.update("I'm tweeting with #gem!")`
I also tried just to do it like this:
Twitter.configure do |config|
config.consumer_key = YOUR_CONSUMER_KEY
config.consumer_secret = YOUR_CONSUMER_SECRET
config.oauth_token = YOUR_OAUTH_TOKEN
config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
end
.. it doesn't work :-( .. I'm a newbie to ruby so perhaps I forgot sth...
I'm really looking forward to your answers. Thank you in advance!!!
I think it was a proxy problem. After deploying it to the cloud it worked!
I am trying to use OmniAuth to handle the OAuth flow for a small-ish Sinatra app. I can get 37signals Oauth to work perfectly, however I'm trying to create a strategy for Freshbooks Oauth as well.
Unfortunately Freshbooks require OAuth requests to go to a user specific subdomain. I'm acquiring the subdomain as an input and I then need to persistently use the customer specific site URL for all requests.
Here's what I've tried up to now. The problem is that the new site value doesn't persist past the first request.
There's to to be a simple way to achieve this but I'm stumped.
#Here's the setup -
def initialize(app, consumer_key, consumer_secret, subdomain='api')
super(app, :freshbooks, consumer_key, consumer_secret,
:site => "https://"+subdomain+".freshbooks.com",
:signature_method => 'PLAINTEXT',
:request_token_path => "/oauth/oauth_request.php",
:access_token_path => "/oauth/oauth_access.php",
:authorize_path => "/oauth/oauth_authorize.php"
)
end
def request_phase
#Here's the overwrite -
consumer.options[:site] = "https://"+request.env["rack.request.form_hash"]["subdomain"]+".freshbooks.com"
request_token = consumer.get_request_token(:oauth_callback => callback_url)
(session[:oauth]||={})[name.to_sym] = {:callback_confirmed => request_token.callback_confirmed?,
:request_token => request_token.token,
:request_secret => request_token.secret}
r = Rack::Response.new
r.redirect request_token.authorize_url
r.finish
end
Ok, here's a summary of what I did for anyone who comes across this via Google.
I didn't solve the problem in the way I asked it, instead I pushed the subdomain into the session and then I overwrite it whenever the site value needs to be used.
Here's the code:
#Monkeypatching to inject user subdomain
def request_phase
#Subdomain is expected to be submitted as <input name="subdomain">
session[:subdomain] = request.env["rack.request.form_hash"]["subdomain"]
consumer.options[:site] = "https://"+session[:subdomain]+".freshbooks.com"
super
end
#Monkeypatching to inject subdomain again
def callback_phase
consumer.options[:site] = "https://"+session[:subdomain]+".freshbooks.com"
super
end
Note that you still have to set something as the site when it's initialised, otherwise you will get errors due to OAuth not using SSL to make the requests.
If you want to see the actual code I'm using it's at: https://github.com/joeharris76/omniauth I'll push the fork up to the main project once I've battle tested this solution a bit more.