Rails 5: Saving external API call to DB - ruby-on-rails

I'm currently trying to save filled out forms from my Typeform. Everything works just fine, except when I try to save the form to the db.
My model Order.rb
class Order < ApplicationRecord
belongs_to :user
include HTTParty
base_uri 'api.typeform.com'
def initialize
token = '############################'
#auth = 'Bearer ' + token
end
def get_orders
response = self.class.get("/forms/######/responses?page_size=25", headers: { "Authorization" => #auth})
end
def save_orders
if response.code.to_i == 200
orders = response.parsed_response
order = response["items"]
order.each do |data|
create!(
email: data["hidden"]["email"]
)
end
else
raise "Error fetching data from Typeform API"
end
end
end

Related

email sending with delay

I wrote my website with Ruby on Rails. I want to add mail services to my app so that at a specific state a user gets an email that contain some details for them. My problem is when I test in development mode I get emails at least with one hours delay and I don't know why? Does it depend on server configuration?
I use Amazon as my email gateway
This is my code for sending emails
module Api
module V1
module User
module DailyCheckin
class Create
attribute :state, ::String
attribute :user, ::User
validates :state, presence: true
validates :user, presence: true
def call
add_error!(I18n.t('messages.daily_checkin.errors.state_invalid')) unless state.present?
#checkin = ::DailyCheckin.create!(
mood: ::Mood.find_by(state: state),
user: user
)
if state == "overwhelmed" || state == "not_coping"
logs = {
user_id: user.id,
email: user.profile.email,
organisation: user.organisation.name,
phone_number: user.profile.phone,
mood: state
}
::Api::V1::ApiGateway::Mail::DailyCheckinRiskNotice.call(logs: logs) if ENV.fetch("SEND_GATEWAY_MAIL", "true").eql? "true"
DailyCheckinRiskWorker.perform_async(user.profile.email, user.profile&.current_first_name, "daily_checkin_risk")
end
add_error!(Helpers::ErrorsHandler.parse(#checkin.errors)) unless #checkin.valid?
context[:mood] = #checkin.mood
end
end
end
end
end
end
and this is my gatways
module Api
module V1
module ApiGateway
module Mail
class DailyCheckinRiskNotice
include HTTParty
attribute :logs
validates :logs, presence: true
def call
options = {
headers: {
'Content-Type' => 'application/json',
'x-api-key' => ENV.fetch('MAIL_API_GATEWAY_API_KEY', '')
},
body: {
email_id: ENV.fetch('USER_ACTIVITY_NOTICE_MAIL_ID', ''),
content: {
logs: logs
}
}.to_json
}
response = HTTParty.post('', options)
add_error!(response.body) unless [201, 200].include?(response.code.to_i)
context[:body] = response.parsed_response
end
end
end
end
end
end
this is my mood model
class Mood < ApplicationRecord
enum state: %i[not_coping overwhelmed ok good great]
has_many :daily_checkins
end
and this my create method that create my logs is state was not coping or overwelmed
def create
result = ::Api::V1::User::DailyCheckin::Create.call(create_checkin_params.merge(user: #current_user))
return render json: Helpers::ErrorsHandler.view_parse(result.errors), status: :bad_request if result.errors
#mood = result.mood
render 'api/v1/moods/show'
end

Rails API expiration for user auth token

I build an Rest API with rails. And I want to implement an expiration for the token. How does it works ?
I don't to implement devise because I don't need that really.
I just want when I create an user he received an token a refresh token.
So it's not really oauth because there are not 3rd party using the api.
This is my user model.
require 'securerandom'
class User
field :auth_token, type: String
field :name, type: String
field :phone, type: String
field :image, type: String
#Generate URLS for different image sizes...
def as_json(options)
json = super
self.image.styles.each do | format |
json = json.merge({"image_"+format[0].to_s => self.image(format[0])})
end
json
end
private
def set_auth_token
return if auth_token.present?
self.auth_token = generate_auth_token
end
def generate_auth_token
SecureRandom.hex(90)
end
end
So simple auth with a simple generated token works. But I think with an expiration token is more secure. Of course the connection is over SSL.
class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
def current_user
#current_user = User.find(params[:user_id])
end
protected
def authenticate
authenticate_token || authentication_request
end
def authenticate_token
authenticate_or_request_with_http_token do |token, options|
User.where(auth_token: token).first
end
end
def authentication_request(controller, realm)
controller.headers["WWW-Authenticate"] = %(Token realm="#{realm.gsub(/"/, "")}")
controller.__send__ :render, :text => "HTTP Token: Access denied.\n", :status => :unauthorized
end
def request_http_token_authentication(realm = "Application")
self.headers["WWW-Authenticate"] = %(Token realm="#{realm.gsub(/"/, "")}")
render :json => {:error => "HTTP Token: Access denied."}, :status => :unauthorized
end
end
When you generate the token, save the time you'd like it to expire:
class User
field :auth_token, type: String
field :token_expiry, type: Time
def set_auth_token
return if auth_token.present? && token_expiry > Time.now
self.auth_token = generate_auth_token
self.token_expiry = Time.now + 1.day
end
Then when you check the token, check the expiry too:
def authenticate_token
authenticate_or_request_with_http_token do |token, options|
user = User.where(auth_token: token).first
user if user.token_expiry > Time.now
end
end

Checking user email calling Closio API in Rails - HTTParty and no method errors

I'm working with a team on checking a user's email input when they sign up for a web app. The user will not be allowed to sign up if their email is not found with the following API call using HTTParty. We are getting method_errors for whatever syntax is first within the function. For, example, in the method below, "include" comes up as an undefined method error.
def email_checker
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
response = HTTParty.get('/api/v1/contact/')
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? :email
errors.add :email, 'According to our records, your email has not been found!'
end
end
UPDATE: So we went with the inline version of using HTTParty and our registrations controller (working with devise) looks like this:
class RegistrationsController < Devise::RegistrationsController
def email_checker(email)
YAML.load(File.read('config/environments/local_env.yml')).each {|k, v| ENV[k.to_s] = v}
api_options = {
query: => {:output => 'json'},
format: :json,
base_uri: 'app.close.io',
basic_auth: ENV["API_KEY"], ' '
}
response = HTTParty.get('/api/v1/contact/', api_options)
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? email
return false
else
return true
end
end
def create
super
if email_checker == false
direct_to 'users/sign_up'
#and return to signup with errors
else
User.save!
end
end
end
We're getting syntax error: "syntax error, unexpected =>" Did we screw up the format?
There are two different ways to use HTTParty, and you're trying to use both. Pick one :).
The class-based method would look something like this:
class CloseIo
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
end
class UserController
def email_checker
response = CloseIo.get('/api/v1/contact/')
# ... the rest of your stuff
end
end
An inline version would look something like this
class UserController
def email_checker
api_options = {
query: :output => 'json',
format: :json,
base_uri: 'app.close.io',
basic_auth: 'insert_api_code_here'
}
response = HTTParty.get('/api/v1/contact/', api_options)
# ... do stuff
end
end

How to test such class behavior in Rspec

I have a class which is responsible for dealing with some response from payments gateway.
Let's say:
class PaymentReceiver
def initialize(gateway_response)
#gateway_response = gateway_response
end
def handle_response
if #gateway_response['NC_STATUS'] != '0'
if order
order.fail_payment
else
raise 'LackOfProperOrder'
# Log lack of proper order
end
end
end
private
def order
#order ||= Order.where(id: #gateway_response['orderID']).unpaid.first
end
end
In payload from payment I've NC_STATUS
which is responsible for information if payment succeed and orderID which refers to Order ActiveRecord class byid`.
I would like to test behavior(in rspec):
If PaymentReceiver receives response where NC_STATUS != 0 sends fail_payment to specific Order object referred by orderID.
How you would approach to testing this ? I assume that also design could be bad ...
You have to make refactorization to remove SRP and DIR principles violations.
Something below I'd say:
class PaymentReceiver
def initialize(response)
#response = response
end
def handle_response
if #response.success?
#response.order.pay
else
#response.order.fail_payment
end
end
end
# it wraps output paramteres only !
class PaymentResponse
def initialize(response)
#response = response
end
def order
# maybe we can check if order exists
#order ||= Order.find(#response['orderID'].to_i)
end
def success?
#response['NCSTATUS'] == '0'
end
end
p = PaymentReceiver.new(PaymentResponse({'NCSTATUS' => '0' }))
p.handle_response
Then testing everything is easy.

422 error when testing stripe webhook

I keep getting a 422 error when testing stripe's webhook for customer.subscription.deleted
I placed this in my config routes
post 'stripewebhooks/receive'
here is my controller
class StripewebhooksController < ApplicationController
Stripe::api_key = ENV['STRIPE_SECRET_KEY']
require 'json'
def receive
data_json = JSON.parse request.body.read
p data_json['data']['object']['customer']
if data_json[:type] == "customer.subscription.deleted"
cancel_subscription(data_event)
end
end
def cancel_subscription(data_event)
#subscription = Subscription.find_by_stripe_customer_token(data['data']['object']['customer'])
#subscription.update_attribute(:subscription_status, "inactive")
end
end
I am unclear on what is suppose to go in the parenthesis after
def cancel_subscription
I am not sure that I am suppose to put data_event or what this means.
When you get a post data from stripe, you need to return a 200 status code from your application.
try this
def receive
data_json = JSON.parse request.body.read
p data_json['data']['object']['customer']
if data_json[:type] == "customer.subscription.deleted"
# Why did you send data_event? send the parsed data_json as parameter
cancel_subscription(data_json)
end
# Return a 200 status code
render :text => '{}', :status => :ok
end

Resources