Integrate instamojo api in rails app - ruby-on-rails

I am learning payment gateway integration in rails.
I chose insta mojo and was working but the documentation they provide is very inconvenient and hard to understand..
https://github.com/AnkurGel/Instamojo-rb#usage
I have no idea where to Set my API keys
require 'Instamojo-rb'
api = Instamojo::API.new do |app|
app.api_key = "api_key-you-received-from-api#instamojo.com"
app.auth_token = "auth_token-you-received-from-api#instamojo.com"
end`
I tried instamojo.rb in initializers and tries to run console but it gives error that no such method exists.

You can put require statement in application.rb or anywhere else so that file is loaded while application is loading.
You can make 'Payment' model in which you can make methods like verify and get details.
Internally in those methods, you will be making API object and using the above code.
class Payment < ActiveRecord::Base
def verify
client = get_intamojo_client
#Some code
end
def get_details
client = get_intamojo_client
#Some code
end
private
def get_instamojo_client
api = Instamojo::API.new(ENV["INSTAMOJO_KEY"],{auth_token: ENV["INSTAMOJO_TOKEN"], endpoint:"https://test.instamojo.com/api/1.1/"})
return api.client
end
end
And to explore what you can do using client object, just use rails console and make a client object there, and use client.public_methods and start exploring.
EDIT:
I think you are using older version of gem i.e 0.1, their documentation is for version > 1.0. To update, use this gem 'Instamojo-rb', '~> 1.1' in gem file and use bundle update.
So for version 0.1, use
api = Instamojo::API.new(ENV["INSTAMOJO_KEY"],{auth_token: ENV["INSTAMOJO_TOKEN"], endpoint:"https://test.instamojo.com/api/1.1/"})
And for versino >= 1.0, use
api = Instamojo::API.new(ENV["INSTAMOJO_KEY"], ENV["INSTAMOJO_TOKEN"], "https://test.instamojo.com/api/1.1/")

Related

Connecting to Google Calendar's API through Rails

I'm creating a really simple Rails application with one specific purpose: add a Calendar event to a Google Calendar account.
I'm following the Ruby Guide from the Google Calendar API.
I was able to run the provided testing code (Ruby only, no framework) but I'm having a hard time accessing the credentials from a Rails project and I'm not sure the proper ("idiomatic"?) way to do it and organize the project.
Part of the process is using OAuth 2.0 since this goal requires access to Google User's private data (both read and write), I'm following the Using OAuth 2.0 for Web Services instructions.
Right now I have several different questions regarding best practices and/or the proper way to organize code:
Google provides a client_secret.json that have the credentials to access the application. Where should I keep it? Should I keep it in a .env file in the Development environment and (in my case) in Heroku's ENV VARS in the Production Environment?
I tried keeping the client_secret.json file in the project's root folder (same path as the Gemfile), added it to the .gitignore but I wasn't able to require "#{Rails.root}/client_secret.json":
/Users/jsoifer/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activesupport-5.0.1/lib/active_support/dependencies.rb:293:in `require': No such file to load -- /Users/jsoifer/Developer/Tiny-Things/tiny-booking/client_secret.json (LoadError)
I created a services/ folder to put the Google Calendar related code inside, I wasn't sure if I should put is in a controller though. How should I organize this?
Important consideration:
I'm not using any other method of Authentication/Authorization such as Devise or others and I'm not planning to do so right now. I just want to get Google's Authorization token and create a Calendar event.
Github Project Link
I was able to figure this out and will post the answer to each of the questions below:
One of the possible locations for the client_secret.json file is config/client_secret.json.
When shipping to Production in Heroku, use ENV Vars.
Require is not the appropriate way to import the credentials in the json file.
Use Google::APIClient::ClientSecrets.load( File.join( Rails.root, 'config', 'client_secret.json' ) ) (assuming the file is indeed in config/.
There are several different alternatives as on how to organize code. I ended up creating a services folder and a google_calendar.rb class holding the authorization logic.
Here's the code:
app/services/google_calendar.rb
require 'google/api_client/client_secrets'
require 'google/apis/calendar_v3'
class GoogleCalendar
# Attributes Accessors (attr_writer + attr_reader)
attr_accessor :auth_client, :auth_uri, :code
def initialize
# ENV: Development
# Google's API Credentials are in ~/config/client_secret.json
client_secrets = Google::APIClient::ClientSecrets.load( File.join( Rails.root, 'config', 'client_secret.json' ) )
#auth_client = client_secrets.to_authorization
# Specify privileges and callback URL
#auth_client.update!(
:scope => 'https://www.googleapis.com/auth/calendar',
:redirect_uri => 'http://localhost:3000/oauth2callback'
)
# Build up the Redirecting URL
#auth_uri = #auth_client.authorization_uri.to_s
end
end
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# Starting action in config/routes.rb
def welcome
# Redirect to Google Authorization Page
redirect_to GoogleCalendar.new.auth_uri
end
def token
# Get a auth_client object from Google API
#google_api = GoogleCalendar.new
#google_api.auth_client.code = params[:code] if params[:code]
response = #google_api.auth_client.fetch_access_token!
session[:access_token] = response['access_token']
# Whichever Controller/Action needed to handle what comes next
redirect_to new_event_path()
end
end

Rails: Convert REST API to websocket client

I have a typical Rails REST Api written for a http consumers. However, it turns out they need web socket API because of the integration POS Machines.
The typical API looks like this;
class Api::Pos::V1::TransactionsController < ApplicationController
before_action :authenticate
def index
#transactions = #current_business.business_account.business_deposits.last(5)
render json: {
status: 200,
number: #transactions.count,
transactions: #transactions.as_json(only: [:created_at, :amount, :status, :client_card_number, :client_phone_number])
}
end
private
def request_params
params.permit(:account_number, :api_key)
end
def authenticate
render status: 401, json: {
status: 401,
error: "Authentication Failed."
} unless current_business
end
def current_business
account_number = request_params[:account_number].to_s
api_key = request_params[:api_key].to_s
if account_number and api_key
account = BusinessAccount.find_by(account_number: account_number)
if account && Business.find(account.business_id).business_api_key.token =~ /^(#{api_key})/
#current_business = account.business
else
false
end
end
end
end
How can i serve the same responses using web-sockets?
P.S: Never worked with sockets before
Thank you
ActionCable
I would second Dimitris's reference to ActionCable, as it's expected to become part of Rails 5 and should (hopefully) integrate with Rails quite well.
Since Dimitris suggested SSE, I would recommend against doing so.
SSE (Server Sent Events) use long polling and I would avoid this technology for many reasons which include the issue of SSE connection interruptions and extensibility (websockets allow you to add features that SSE won't support).
I am almost tempted to go into a rant about SSE implementation performance issues, but... even though websocket implementations should be more performant, many of them suffer from similar issues and the performance increase is often only in thanks to the websocket connection's longer lifetime...
Plezi
Plezi* is a real-time web application framework for Ruby. You can either use it on it's own (which is not relevant for you) or together with Rails.
With only minimal changes to your code, you should be able to use websockets to return results from your RESTful API. Plezi's Getting Started Guide has a section about unifying the backend's RESTful and Websocket API's. Implementing it in Rails should be similar.
Here's a bit of Demo code. You can put it in a file called plezi.rb and place it in your application's config/initializers folder...
Just make sure you're not using any specific Servers (thin, puma, etc'), allowing Plezi to override the server and use the Iodine server, and remember to add Plezi to your Gemfile.
class WebsocketDemo
# authenticate
def on_open
return close unless current_business
end
def on_message data
data = JSON.parse(data) rescue nil
return close unless data
case data['msg']
when /\Aget_transactions\z/i
# call the RESTful API method here, if it's accessible. OR:
transactions = #current_business.business_account.business_deposits.last(5)
write {
status: 200,
number: transactions.count,
# the next line has what I think is an design flaw, but I left it in
transactions: transactions.as_json(only: [:created_at, :amount, :status, :client_card_number, :client_phone_number])
# # Consider, instead, to avoid nesting JSON streams:
# transactions: transactions.select(:created_at, :amount, :status, :client_card_number, :client_phone_number)
}.to_json
end
end
# don't disclose inner methods to the router
protected
# better make the original method a class method, letting you reuse it.
def current_business
account_number = params[:account_number].to_s
api_key = params[:api_key].to_s
if account_number && api_key
account = BusinessAccount.find_by(account_number: account_number)
if account && Business.find(account.business_id).business_api_key.token =~ /^(#{api_key})/
return (#current_business = account.business)
end
false
end
end
end
Plezi.route '/(:api_key)/(:account_number)', WebsocketDemo
Now we have a route that looks something like: wss://my.server.com/app_key/account_number
This route can be used to send and receive data in JSON format.
To get the transaction list, the client side application can send:
JSON.stringify({msg: "get_transactions"})
This will result in data being send to the client's websocket.onmessage callback with the last five transactions.
Of course, this is just a short demo, but I think it's a reasonable proof of concept.
* I should point out that I'm biased, as I'm Plezi's author.
P.S.
I would consider moving the authentication into a websocket "authenticate" message, allowing the application key to be sent in a less conspicuous manner.
EDIT
These are answers to the questions in the comments.
Capistrano
I don't use Capistrano, so I'm not sure... but, I think it would work if you add the following line to your Capistrano tasks:
Iodine.protocol = false
This will prevent the server from auto-starting, so your Capistrano tasks flow without interruption.
For example, at the beginning of the config/deploy.rb you can add the line:
Iodine.protocol = false
# than the rest of the file, i.e.:
set :deploy_to, '/var/www/my_app_name'
#...
You should also edit your rakefile and add the same line at the beginning of the rakefile, so your rakefile includes the line:
Iodine.protocol = false
Let me know how this works. Like I said, I don't use Capistrano and I haven't tested it out.
Keeping Passenger using a second app
The Plezi documentation states that:
If you really feel attached to your thin, unicorn, puma or passanger server, you can still integrate Plezi with your existing application, but they won't be able to share the same process and you will need to utilize the Placebo API (a guide is coming soon).
But the guide isn't written yet...
There's some information in the GitHub Readme, but it will be removed after the guide is written.
Basically you include the Plezi application with the Redis URL inside your Rails application (remember to make sure to copy all the gems used in the gemfile). than you add this line:
Plezi.start_placebo
That should be it.
Plezi will ignore the Plezi.start_placebo command if there is no other server defined, so you can put the comment in a file shared with the Rails application as long as Plezi's gem file doesn't have a different server.
You can include some or all of the Rails application code inside the Plezi application. As long as Plezi (Iodine, actually) is the only server in the Plezi GEMFILE, it should work.
The applications will synchronize using Redis and you can use your Plezi code to broadcast websocket events inside your Rails application.
You may want to have a look at https://github.com/rails/actioncable which is the Rails way to deal with WebSockets, but currently in Alpha.
Judging from your code snippet, the client seems to only consume data from your backend. I'm skeptical whether you really need WebSockets. Ιf the client won't push data back to the server, Server Sent Events seem more appropriate.
See relevant walk-through and documentation.

Uninitialized Constant GooglePlaces

I am currently using the google_places gem to try to access the places API. I am using the following code to get results:
class PlacesController < ApplicationController
def index
if params[:search]
#client = ::GooglePlaces::Client.new(Rails.application.secrets.places_api_key)
#places = #client.spots_by_query(params[:search])
end
end
end
I am running into an error of uninitialized constant GooglePlaces, which is replaced with PlacesController::GooglePlaces if I don't scope out. I believe this is a scoping issue, but nothing that I have tried fixes the issue. I am following the directions in the repo's readme and assuming that I don't have to include the source in the lib directory of my site. I can use the gem correctly from the rails console.
To use this API in rails application you need to use google_places gem.
add in gem file and run bundle install and restart the server once
gem 'google_places'
Next Create a project in google console and generate secret key .
https://code.google.com/apis/console
https://developers.google.com/places/documentation/
Finally restart the server
The docs said the API auth call should be:
#client = GooglePlaces::Client.new(Rails.application.secrets.places_api_key)

How to make a Rails 4 API with Mongoid ORM, an OAuth2 Provider?

I am trying to secure a Rails 4 API by making it a OAuth2 Provider.
Added the gem Mongoid '4.0.0' (from the master branch of the Git Repo) to make it work with Rails 4.
Now I wish to use Doorkeeper gem to make the API an OAuth2 Provider.
I guess Doorkeeper doesn;t support Mongoid 4
(Source: https://github.com/applicake/doorkeeper/issues/224)
Moreover, I can't use Mongoid 3.1.2 as this wont work in Rails 4.
I prefer not to use the gem 'oauth-plugin' due to too much of Boilerplate code it injects.
Please suggest, Is there anything I can do to get it working?
Thank you in advance! :-)
Moped’s BSON has been removed of bson gem 2.0, but you may add this manually.
Create
config/initializers/bson/object_id.rb
Into file add:
module Moped
module BSON
ObjectId = ::BSON::ObjectId
class Document < Hash
class << self
def deserialize(io, document = new)
__bson_load__(io, document)
end
def serialize(document, io = "")
document.__bson_dump__(io)
end
end
end
end
end
Link to original article

flickr-fu simple example not working

I'm using flickr-fu gem within a rails application for flickr api integration. I'm following the sample code for setting up a web app shown below:
def flickr_create
flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
redirect_to flickr.auth.url(:read)
end
def flickr_callback
flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
flickr.auth.frob = params[:frob]
current_user.update_attribute :flickr_token, flickr.auth.token.token
flash[:notice] = "Succesfully authenticated with Flickr"
redirect_to :flickr_stream
end
I've registered flickr_callback as the callback method that flickr calls after the authorization process.
The problem is with the line in flickr_callback when I try and assign params[:frob] to flickr.auth.frob. I get the following error:
undefined method `frob=' for Flickr::Auth:0x24b3640
Even if I just require 'flickr_fu' from within console, create a new flickr instance, and attempt to assign to frob, I get the same error. I took a look at the gem source on github, and the setter frob= is set within the Flickr::Auth module, so I'm clueless as to where the error is. The API calls work successfully and the flickr object is initialized fine.
The issue is that the flickr-fu gem from gemcutter or github is at version 0.1.4, and the frob setter method wasn't implemented until subsequent version. Instead install the gem commonthread-flickr_fu v0.3.0 from github, and the frob is writeable.

Resources