Integration tests create test users on Stripe, how to stop or stub out - ruby-on-rails

I'm using stripe on a project. I'm using Railscasts #288 (http://railscasts.com/episodes/288-billing-with-stripe) as a guide. I have it so that once a user registers with a valid username and password I will create their Stripe customer account.
After a few runs of my integration test I can see that I have many users created in my test account for Stripe. How do I structure the integration test so that it goes through my registration process as a typical user would, but without creating the Stripe account with Stripe?

I'm coming a little late to the game, but check out StripeMock. It is made specifically for this purpose.
StripeMock.start
Stripe::Customer.create({
id: '123',
email: 'someone#something.com',
card: 'void_card_token',
subscriptions: {
data: [{
plan: {
name: 'Some Subscription Plan',
currency: 'usd',
amount: 1000
},
start: 1410408211,
status: 'active',
current_period_start: 1410408211,
current_period_end: 1413000211
}]
}
})
test... test... test...
StripeMock.stop

i dealt with that by making all my customers created through the testing have "deletable" in their email address, and adding these lines to my spec_helper.
config.after(:suite) do
custs = Stripe::Customer.all(limit: 100).data
custs.keep_if { |c| c.email.match( /deletable/ ) }
custs.each { |c| c.delete }
end

This is typically done with a tool like WebMock which intercepts the HTTP request and returns a response you provide. The VCR gem makes this process easier by recording and replaying HTTP requests using WebMock (or optionally FakeWeb) under the hood. There is a Railscast on VCR, but it is a bit out of date. Take care not to record any sensitive data (i.e. api keys) by using the filter_sensitive_data configuration option.

It's difficult to really test an integration without making your tests as realistic as possible. Therefore, I suggest that you let stripe create the test customer accounts, but make use of the webhooks to automatically delete them.
Specifically, you would handle the customer.created event. If event->livemode == false, send a request back to the api to delete the customer.
This way, you run through the entire process as you test, while only keeping customers that were created in live mode.

Related

The application goes offline when trying to send more than thousands of emails in Rails with AWS SES

I have implemented a platform using rails, and the goal is to send thousands of emails to customers with one click. The concept is that an email array runs each loop and inside each loop runs send email functionality like below.
#emails = ['abc#gmai.com', 'abc#example.com'] # More than 3 thousands
#emails.each do |email|
aws_email_sender(email, #email_subject, #email_body_html)
end
And the email function is like below:
def aws_email_sender(recipient, subject, htmlbody)
sender = "hello#example.com"
awsregion = "ap-west-1"
# The HTML body of the email.
htmlbodycontent = "#{htmlbody}"
# The email body for recipients with non-HTML email clients.
textbody = "This email was sent with Amazon SES using the AWS SDK for Ruby."
# Specify the text encoding scheme.
encoding = "UTF-8"
# Create a new SES resource and specify a region
ses = Aws::SES::Client.new(region: awsregion)
# Try to send the email.
begin
# Provide the contents of the email.
resp = ses.send_email({
destination: {
to_addresses: [recipient]
},
message: {
body: {
html: {
charset: encoding,
data: htmlbodycontent
},
text: {
charset: encoding,
data: textbody,
},
},
subject: {
charset: encoding,
data: subject,
},
},
source: sender,
});
# If something goes wrong, display an error message.
rescue Aws::SES::Errors::ServiceError => error
puts "Email not sent. Error message: #{error}"
end
end
The email is sending well by AWS but my rails application has gone down like
A timeout occurred, error code 524
I couldn't get the breaking point, why has my application gone down every time?
Thanks in Advance
If 524 is an HTTP status code then it means...
Cloudflare was able to make a TCP connection to the website behind them, but it did not reply with an HTTP response before the connection timed out.
Meaning your Rails app is behind a Cloudflare proxy. Cloudflare received an HTTP request, forwarded it to your app, waited around for your app to respond, but your app never did. A more detailed explanation can be found here.
Probably because it's trying to send emails to 3000 people one-by-one.
There's two strategies to fix this.
Use Bulk Email
Since the content of the email is the same for everyone, use an email template to send bulk email using the #send_bulk_templated_email method.
You can send to up to 50 addresses at a time, so use #each_slice to loop through emails in slices of 50.
This will be more efficient, but your app will still be waiting around for 3000/50 = 60 AWS API calls. At worst it will still time out. At best the user will be waiting around for a form submission.
Use A Background Job
Anytime your app needs to do something that might take a lot of time, like using a service or a large database query, consider putting it into a background job. The Rails app queues up a job to send the emails, and then it can respond to the web request while the mailing is handled in the background. This has other advantages: errors calling the service won't cause an error for the user, and failed jobs due to a temporary service outage can automatically be retried.
In Rails this is done with ActiveJob and you could write a job class to send your mail.
Use ActionMailer
However, Rails also offers a class specifically for sending email in the background: ActionMailer. You can have ActionMailer use AWS with the aws-sdk-rails gem.
config.action_mailer.delivery_method = :ses

How do I get the JSON response from Dialogflow with Rails?

I understand the whole process of dialogflow and I have a working deployed bot with 2 different intents. How do I actually get the response from the bot when a user answers questions? (I set the bot on fulfillment to go to my domain). Using rails 5 app and it's deployed with Heroku.
Thanks!
If you have already set the GOOGLE_APPLICATION_CREDENTIALS path to the jso file, now you can test using a ruby script.
Create a ruby file -> ex: chatbot.rb
Write the code bellow in the file.
project_id = "Your Google Cloud project ID"
session_id = "mysession"
texts = ["hello"]
language_code = "en-US"
require "google/cloud/dialogflow"
session_client = Google::Cloud::Dialogflow::Sessions.new
session = session_client.class.session_path project_id, session_id
puts "Session path: #{session}"
texts.each do |text|
query_input = { text: { text: text, language_code: language_code } }
response = session_client.detect_intent session, query_input
query_result = response.query_result
puts "Query text: #{query_result.query_text}"
puts "Intent detected: #{query_result.intent.display_name}"
puts "Intent confidence: #{query_result.intent_detection_confidence}"
puts "Fulfillment text: #{query_result.fulfillment_text}\n"
end
Insert your project_id. You can find this information on your agent on Dialogflow. Click on the gear on the right side of the Agent's name in the left menu.
Run the ruby file in the terminal or in whatever you using to run ruby files. Then you see the bot replying to the "hello" message you have sent.
Obs: Do not forget to install the google-cloud gem:
Not Entirely familiar with Dilogflow, but if you want to receive a response when an action occurs on another app this usually mean you need to receive web-hooks from them
A WebHook is an HTTP callback: an HTTP POST that occurs when something happens; a simple event-notification via HTTP POST. A web application implementing WebHooks will POST a message to a URL when certain things happen.
I would recommend checking their fulfillment documentation for an example. Hope this helps you out.

shopify application charge failing to save

Below is my code for a Shopify one-time-application-charge in Ruby. I followed the shopify "add billing to your app" page (https://help.shopify.com/api/tutorials/adding-billing-to-your-app) for the code, except didn't need a recurring charge. I have also found someone else who posted their one-time-charge code which looks very similar to mine (https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/one-time-application-charge-example-for-shopify-rails-app-489347).
def create_application_charge
application_charge = ShopifyAPI::ApplicationCharge.new(
name: "MyApp",
price: 0.09,
return_url: "https:\/\/myapp.herokuapp.com\/activatecharge",
test: true)
save = application_charge.save
if save
redirect application_charge.confirmation_url
return
end
flash[:error] = "The save worked: #{save}"
end
The flash always responds as false. Is there a failure at authentication that would prevent this? Or something to get the store to accept an application charge? I'm at a loss as to why this does not work.
Any help would be greatly appreciated, thank you.
The primary issue appears to be that the minimum charge you can request is $0.50, for which I wasn't meeting with my choice of using $0.09 for my test.

Rails ActionCable and Ember CLI app - Resource Bottlenecks

We've successfully implemented real time updates in our app using ActionCable in Rails and implemented the consumer as a client service in Ember CLI, but am looking for a better, less-expensive approach.
app/models/myobj.rb
has_many :child_objs
def after_commit
ActionCable.server.broadcast("obj_#{self.id}", model: "myobj", id: self.id)
self.child_objs.update_all foo: bar
end
app/models/child_obj.rb
belongs_to :myobj
def change_job
self.job = 'foo'
self.save
ActionCable.server.broadcast("obj_#{self.myobj.id}", model: "child_obj", id: self.id)
end
frontend/app/services/stream.js
Here we're taking the model and id data from the broadcast and using it to reload from the server.
import Ember from 'ember';
export default Ember.Service.extend({
store: Ember.inject.service(),
subscribe(visitId) {
let store = this.get("store")
MyActionCable.cable.subscriptions.create(
{channel: "ObjChannel", id: objId}, {
received(data) {
store.findRecord(data.model, data.id, {reload: true});
}
}
);
},
});
This approach "works" but feels naïve and is resource intensive, hitting our server again for each update, which requires re-authenticating the request, grabbing data from the database, re-serializing the object (which could have additional database pulls), and sending it across the wire. This does in fact cause pool and throttling issues if the number of requests are high.
I'm thinking we could potentially send the model, id, and changeset (self.changes) in the Rails broadcast, and have the Ember side handle setting the appropriate model properties. Is this the correct approach, or is there something else anyone recommends?
You should be fine with sending whole entity payload with your change event via sockets. Later you can push payload to the store - create new records or update existing. This way you'll avoid additional server requests.

"The token is invalid" when trying to setup Paypal recurring payments with ActiveMerchant

I feel like a lot of the documentation on this is outdated, but this is what I have been trying so far:
I am using the ActiveMerchant::Billing::PaypalExpressGateway gateway.
First I setup the purchase and redirect the user to Paypal:
response = gateway.setup_purchase price,
return_url: <confirm url>,
cancel_return_url: <cancel url>,
items: [
{
name: 'My Item',
quantity: 1,
description: "My Item Description",
amount: price
}
]
redirect_to gateway.redirect_url_for(response.token)
This works, I can sign in as a sandboxed buyer and confirm the payment, which brings me back to <confirm url> from above. In the confirmation, I do:
response = gateway.recurring price, nil,
token: params[:token],
period: 'Year',
frequency: 1,
start_date: Time.now,
description: 'My Item Subscription'
When I do this, I receive an invalid token error from Paypal in the response variable. The token seems to be fine, it is present in the URL when I am brought back to the confirmation URL. I'm then taking it directly (params[:token]) and sending it back to Paypal.
Am I doing something completely wrong? Like I said, it seems like a lot of the documentation for this type of process is outdated (or maybe what I am trying is the stuff that is outdated...)
After looking through the source code for ActiveMerchant's Paypal express checkout gateway, I came to the conclusion that it's simply outdated when dealing with recurring payments. I switched to the paypal-recurring gem instead and everything worked fine.

Resources