Reputation: 17
I have a working terminal-command which provides me with an json containing the access token (which is valid only X-minutes):
curl -X POST -u [cliend_id]:[secret] "url_to_get_token"
What I want is to generate the Access-Token dynamically in my Controller (and save it for X-minutes in my session - but this is only a plus)
I tried: exec("the terminal command")
which shuts down my local server but is in general a bad solution.
Does anyone knows a solution? This should be very basic, but I am a rails newbe.
Thanks a lot in advance!
Upvotes: 0
Views: 2133
Reputation: 1848
Since you can get the token calling a URL, what you have to do is to perform that same call but within Rails with any http library, instead of doing an exec
call.
I'm assuming that getting the token is a means to an end, and that end is to perform some action, for example "Get Elements", on a service, which I'll call "My Service". I'm also assuming that "My Service" doesn't have a Ruby client already. If the service you're calling has a Ruby client, use it.
I'm a defender of Service Objects so I'll propose a solution creating Service Objects that will be called from your controller.
The high level idea is that there's a MyServiceClient
object with all the logic to perform actions to your service, including getting the token. There's also a model, TokenStorage
, responsible of only storing and validating tokens against the database. Then, SomeController
uses MyServiceClient
and TokenStorage
to perform and validate actions against your service.
A separation like this keeps objects very small and doesn't pollute neither your controller nor your model with token rotation logic or intrinsic details about "My Service".
# Gemfile
gem 'http'
# app/controllers/some_controller.rb
class SomeController < ActionController::Base
def index
@elements = my_service_client.get_elements
# now the view will have access to the elements from your service
end
private
def my_service_client
@_my_service_client ||= MyServiceClient.new(TokenStorage)
end
end
# app/models/token_storage.rb
class TokenStorage < ActiveRecord::Base
def self.valid?
expiration = select(:expiration).order(expiration: :desc).first
expiration && Time.now < expiration
end
def self.token
select(:token).order(expiration: :desc).first
end
def self.store(token, expiration)
create(token: token, expiration: expiration)
end
end
# lib/my_service_client.rb
require 'http'
class MyServiceClient
def initialize(token_storage)
@token_storage = token_storage
end
def get_elements
HTTP.auth(token)
.get(Config.my_service_url_to_get_elements)
end
private
attr_reader :token_storage
def token
if token_storage.valid?
token_storage.token
else
rotate_token
end
end
def rotate_token
token, expiration = create_token
token_storage.store(token, expiration)
token
end
def create_token
parse_response(get_token_from_service)
end
def get_token_from_service
# Try to store client_id and secret in environment variables rather than in
# the codebase.
HTTP.basic_auth(user: Config.my_service_client_id,
pass: Config.my_service_secret)
.post(Config.my_service_url_to_get_token)
end
def parse_response(response)
# Here you parse the response according to your interface, and get the token
# value `token` and expiration date `expiration`.
[token, expiration]
end
end
Upvotes: 1