Stripe success_url format in a rails app not creating correct URL - ruby-on-rails

I have an app that uses Stripe Checkout and creates a Stripe session and then redirects to checkout.
In my controller, this code works fine:
session = Stripe::Checkout::Session.create(
payment_method_types: ['card'],
subscription_data: {
items: [{ plan: stripe_plan }],
},
customer: stripe_customer_id,
customer_email: stripe_customer_email,
client_reference_id: current_user.id,
success_url: "http://localhost:3000/welcome_new_subscriber?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "http://localhost:3000/charges/new?stripe_plan=" + stripe_plan,
)
And correctly redirects to the URL:
http://localhost:3000/welcome_new_subscriber?session_id=cs_test_abcd1234
When I change the success_url line to the following (as advised on a few websites) it does not work:
success_url: welcome_new_subscriber_url(:session_id => '{CHECKOUT_SESSION_ID}'),
The URL resolves to:
http://localhost:3000/welcome_new_subscriber?session_id=%7BCHECKOUT_SESSION_ID%7D
It seems the {CHECKOUT_SESSION_ID} is not resolving correctly.
Any idea what I am doing incorrectly - I've tried every syntax change I can think of?

When you use
welcome_new_subscriber_url(:session_id => '{CHECKOUT_SESSION_ID}')
Rails is trying to be helpful by URI-escaping { and }. However the Stripe gem using these as special characters to know where to replace template variables.
So you could just use
welcome_new_subscriber_url + "?session_id={CHECKOUT_SESSION_ID}"
Not the most elegant thing, but then again Stripe's system here is kinda wierd (why don't they let you just pass CHECKOUT_SESSION_ID yourself?), so we gotta make do

Related

Editing Google Calendar Event Meets URI With External Link via API

I've had code that has been working for the last year or so, that adds a new Google Meets Entry Point with my own custom URI to the Google Calendar Event via the Google Calendar API.
For example if I click on "Join with Google Meet" below it does not go to a meets.google.com link like usual, because I replaced it with my own custom link.
Unfortunately for some reason in the past couple weeks this stopped working. Now when my code tries to edit the URI for the meet, it returns this error: Google::Apis::ClientError (invalid: Invalid Value). I haven't changed the code in months and this only started happening recently.
Here is what the code looks like:
def update_event_meet_url(service, event, send_updates = "all")
entry_points = [
Google::Apis::CalendarV3::EntryPoint.new(
entry_point_type: "video",
label: meeting_url,
uri: meeting_url,
),
]
if original_phone_info.present?
entry_points << Google::Apis::CalendarV3::EntryPoint.new(
entry_point_type: original_phone_info["entry_point_type"],
label: original_phone_info["label"],
uri: original_phone_info["uri"],
pin: original_phone_info["pin"],
region_code: original_phone_info["region_code"],
)
end
event_changes = {
conference_data: Google::Apis::CalendarV3::ConferenceData.new(entry_points: entry_points),
}
updated_event = Google::Apis::CalendarV3::Event.new(event_changes)
service.patch_event(
gcalendar_id,
event.id,
updated_event,
conference_data_version: 1,
send_updates: send_updates,
)
end
I know the problem is with the video entry point because I replaced the meeting_url with a working https://meets.google.com link and it worked. But if I try anything else that is not meets.google.com it errors.
I'm using this Ruby gem https://github.com/googleapis/google-api-ruby-client.
Any help would be appreciated! Thanks!
Contacted google support and looks like there was a recent release that changed the behavior of conferenceData.conferenceSolution.key.type. More info here: https://developers.google.com/calendar/releases#january_11_2021)we
Basically I needed to change my conference solution key type to addOn instead of hangoutsMeet. The subsequent problem I had was that I still needed a hangoutsMeet link, since the third party url I'm using would eventually redirect to the meets.google.com link. And the only way to get a hangoutsMeet link is to create the initial event with conferenceData.conferenceSolution.key.type = hangoutsMeet.
So what I did was create the google event with conferenceData.conferenceSolution.key.type = 'hangoutsMeet' and then I did a subsequent patch_event call that set the initial hangoutsMeet conference solution to null and created a new conferenceSolution of type addOn. That way I could store the original meets.google.com link and then use that link for the redirect from my third party link.
def update_event_meet_url(service, event, send_updates = "all")
entry_points = [
Google::Apis::CalendarV3::EntryPoint.new(
entry_point_type: "video",
label: meeting_url,
uri: meeting_url,
),
]
conference_solution_key = Google::Apis::CalendarV3::ConferenceSolutionKey.new(type: "addOn")
conference_solution =
Google::Apis::CalendarV3::ConferenceSolution.new(key: conference_solution_key)
event_changes = {
conference_data: Google::Apis::CalendarV3::ConferenceData.new(
conference_solution: conference_solution,
entry_points: entry_points,
create_request: nil,
),
}
updated_event = Google::Apis::CalendarV3::Event.new(event_changes)
service.patch_event(
gcalendar_id,
event.id,
updated_event,
conference_data_version: 1,
send_updates: send_updates,
)
end

"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.

Put_connections to create a new event with Koala?

I'm trying to create a new event using the Koala gem and it's returning with the same error I got when I tried to update an event with an incorrectly formatted datetime value.
I can update just fine now but still cannot create an event.
Here's the code I use on my update method which works:
start_time = safe_params[:start_time].in_time_zone
end_time = safe_params[:end_time].in_time_zone
graph.put_connections(safe_params[:fb_id], "event", {
name: safe_params[:name],
description: safe_params[:description],
privacy: safe_params[:privacy]
})
And here's the code I'm trying to use to create a new event object:
graph.put_connections("/me/events", "event", { #this is the line that errors
name: safe_params[:name],
description: safe_params[:description],
privacy: safe_params[:privacy]
})
According to Facebook's documentation on creating an event (https://developers.facebook.com/docs/graph-api/reference/user/events/), I should be able to create a new event just by initiating a post to /me/events. Anyone have any idea?
I also tried:
graph.put_connections("/"+current_user.fb_id.to_s+"/events", "event", {
Thanks!
What happens if you do something like this?
graph.put_connections("me", "events", {
name: safe_params[:name],
description: safe_params[:description],
privacy: safe_params[:privacy],
start_time: ...,
end_time: ...
})
So after messing with Facebook's Graph Explorer and attempting hundreds of different combinations with put_connections I decided to make a straight graph_call using Koala.
Finally got an ID response back. I almost cried. Thought I'd share with the community in case there's someone else trying to do the same thing.
event_response = graph.graph_call("/me/events",{
name:safe_params[:name],
start_time: safe_params[:start_time],
privacy_type: safe_params[:privacy],
access_token: current_user.oauth_token}, "POST")
safe_params[:fb_id] << event_response["id"]
#event = Event.create safe_params
I make the call in a stored variable event_response because the Facebook Id returned is used in my app.
First thing I found out: despite using "privacy" as the name of the privacy field when GETting from Facebook and saying so in their documentation, "privacy_type" is actually what you want (found this out in another SO post).
The second thing I found out is even though you are authenticated (have a user token) when you make a graph_call you STILL need to pass along the current_user access token along with making a POST graph_call.
Hope this helps someone!

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

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.

OmniAuth - Facebook login not supplying email in user_info

I'm using OmniAuth, and after logging in via Facebook, I get my omniauth.auth key, which looks like this:
user_info:
name: Tim Sullivan
urls:
Facebook: http://www.facebook.com/...
Website:
nickname: ...
last_name: Sullivan
first_name: Tim
uid: "123456789"
credentials:
token: [some token]
extra:
user_hash:
name: Tim Sullivan
timezone: -5
gender: male
id: "123456789"
last_name: Sullivan
updated_time: 2010-12-30T00:52:39+0000
verified: true
locale: en_US
link: http://www.facebook.com/...
email: tim#myemailaddress.com
first_name: Tim
provider: facebook
Now, according to the docs, the email should be in the user_info section, but it isn't. It is, however, in the extra/user_hash section. Since I'm stripping extra, it's not getting stored, so later on down the pipe I'm having problems. I could add it myself, but that doesn't explain why it's not there in the first place.
Why isn't email being put into the user_info section? A bug? Undocumented change?
moved to
email = omniauth["extra"]["raw_info"]["email"]
The hash "info" contains all the information of the User:
email = omniauth["info"]["email"]
I think the doc is not up to date. I usually get it from the extra hash before removing it.
email = omniauth["extra"]["user_hash"]["email"]
While omniauth["info"] used to and should contain the information, I have noticed that facebook seems to be giving me errors with the email which is linked to a facebook bug/(feature?). So I get intermittent errors with this hash where the email is not present which breaks everything.
After much debugging I found that the safest way to not break my code is to call the FB API with Koala or just good ol REST and get the information needed for login if omniauth["info"] does not contain the information you need.
We are using omniauth with the FB JSDK and I couldn't get the email to come back because I had overlooked the fact that FB.login() requires a 'scope' opts.
FB.login(function(response) {
// handle the response
}, {scope: 'email,user_likes'});
After adding the opts (even though the scope was set up on the server) everything was fixed.
https://developers.facebook.com/docs/reference/javascript/FB.login/v2.2#permissions
Since you're using Rails and not JavaScript (another person answered but for JS), you need to specifically ask for email to be returned from the info field hash as it isn't by default. You set this up in your config/initializers/omniauth.rb file like so:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, Rails.application.secrets.omniauth_provider_key, Rails.application.secrets.omniauth_provider_secret,
:scope => 'email', :display => 'popup', :info_fields => 'name,email'
end
This info is kind of hidden at the very end of the Configuring section on the omniauth-facebook gem's GitHub readme.

Resources