Stripe on Ruby on Rails - Creating config/initializers/stripe.rb - ruby-on-rails

Following the Stripe setup document for Ruby on Rails (https://stripe.com/docs/checkout/rails), it says that the config/initializers/stripe.rb will be created when the app is started.
I have shutdown the server and the restarted the server several times, but this file isn't being created under the path identified in the documentation.
What am I doing wrong? Appreciate the help.

Create this file manually. Initializers are not generated on application start. They are read by Rails to configure your specific application.
Create config/initializers/stripe.rb and fill it with the following.
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
Set your secret key and publishable key in your ENVs. Restart your application after the change or you won't see any difference.
I can see how you would be confused, Stripe documentation says "An initializer is a good place to set these values, which will be provided when the application is started." They mean the values you set in that file will be provided to the application instance.

I really disliked the anti-pattern that Stripe Gem has, instead I end up overriding the Stripe::StripeConfiguration (even here we can see naming redundancy 😞) Here is my solution:
## Stripe Initializer
## {Rails.root}/config/initializers/stripe.rb
# frozen_string_literal: true
require 'stripe'
module Stripe
class StripeConfiguration
def api_key=(key_value)
#api_key = key_value || Rails.application.credentials.stripe.secret_key
end
end
end
Rails.configuration.stripe = {
publishable_key: Rails.application.credentials.stripe.secret_key,
secret_key: Rails.application.credentials.stripe.secret_key
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
NOTE: for the Stripe team, their implementation in no way gives an extra security layer, anyone who can have access to the console/credentials will be able to read it so it makes no sense that they override it on each request. You can always assign an attribute with an operator.
PS: I'm working on an app that would improve that security (Comming Soon)

Related

Ruby on rails - Stripe : "you did not set a valid publishable key"

I have a problem I am following step by step this tutorial to include the gem stripe to my rails application : https://stripe.com/docs/checkout/rails
But I have an issue when I launch my payment:
you did not set a valid publishable key. Call Stripe.setPublishableKey() with your publishable key.
The tutorial I am following doesn't use this method Stripe.setPublishableKey() and it seems working as well ...
I am using a .env file to get the API keys and I use the test keys from the tutorial.
Any idea for the solution ?!
Thank you very much :) If you need more information please tell me
My actual code is a copy/paste from the tutorial I use.
Edit 1
I don't understand why but it working when I push the project on Heroku ... but I still don't understand why it's failing on local
From the guide you linked:
The application makes use of your publishable and secret API keys
to interact with Stripe. An initializer is a good place to set these
values, which will be provided when the application is started.
Add the following to config/initializers/stripe.rb:
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
These keys values are pulled out of environmental variables so as not
to hardcode them. It’s best practice not to write API keys into your
code, where they could easily wind up in source control repositories
and other non-private destinations.
Have you added that data into config/initializers/stripe.rb ?
If so, you may need to restart your server as the files in config/initializers are only loaded on server startup
I am using a .env file to get the API keys and I use the test keys from the tutorial.
Rails don't autoload environment variables from .env file. So, in the tutorial author set required variables from the console before server start, but you use .env file.
To fix that use gem dotenv-rails: just add in your Gemfile(not need add the same lines as in gem description)
I was able to overcome the same type of error in another tutorial by changing the last line of the stripe.rb file to:
Stripe.api_key = Rails.application.credentials.stripe[:secret_key]
with the key being saved in the credentials.yml.enc file in rails 5.2

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

Ruby on Rails Configuration - Plaid Gem

I am trying to integrate the plaid gem into one of my projects. From the docs it says to configure it as such.
https://github.com/plaid/plaid-ruby
Plaid.config do |p|
p.customer_id = 'Plaid provided customer ID here'
p.secret = 'Plaid provided secret key here'
p.environment_location = 'URL for the development or production environment'
end
My question is what file should I have this code? Should it go in my application.rb? config.rb? Just want to make sure I'm following convention. Thanks!
You should create this file in config/initializers directory with any file name i.e. plaid.rb.
FYI: Using Initializer Files.

RoR, Fog: Getting Started with Fog

I just installed the gem asset_sync and I am trying to get set up with my AWS account. When I run bundle exec rake assets:precompile I get the following errror:
AssetSync::Config::Invalid: Fog provider can't be blank, Fog directory can't be blank
I understand the simply reason that I am getting this error, namely that I havent pushed the Fog provider or directory to heroku. What I am stumped about is where to put the Following code (Taken from the Fog README). In config/initializers/fog.rb? Is this all I need to do to start using fog, other than installing the gem?
require 'rubygems'
require 'fog'
# create a connection
connection = Fog::Storage.new({
:provider => 'AWS',
:aws_access_key_id => YOUR_AWS_ACCESS_KEY_ID,
:aws_secret_access_key => YOUR_AWS_SECRET_ACCESS_KEY
})
# First, a place to contain the glorious details
directory = connection.directories.create(
:key => "fog-demo-#{Time.now.to_i}", # globally unique name
:public => true
)
not a problem, getting started tends to be the hardest part.
The answer is, it depends. I'd actually venture to say it would be best to put this in your environment based initializers, ie config/init/development or config/init/production, etc. Relatedly, you probably will not want to generate a new directory every time you start your app (there is an account level limit of 100 total I believe). So you might want to either set a key for each environment for that create or simply create the directory somewhere outside the initializers (and within the initializer you can assume it exists).
If you want to use that directory directly, you'll still need to create a reference, but you can create a local reference without making any api calls with #new like this:
directory = connection.directories.new(:key => ...)
As for asset_sync, it needs those keys and a reference to the directory key, which you will probably want to provide via ENV vars (to avoid checking your credentials into version control). You can find details on which keys and how to set them here: https://github.com/rumblelabs/asset_sync#built-in-initializer-environment-variables (the readme also describes how to do it via initializers, but that probably isn't the best plan).
Hope that helps!

Passing variables to config/environments/demo.rb from the Rails app

I have been struggling with a problem for the past days in a Ruby on Rails App I'm currently working on. I have different countries and for each country we use different Amazon S3 buckets. Amazon S3 key credentials are stored as constants in config/environments/environment_name.rb(ex:demo.rb) There is no way for me to determine which country we are operating from the config file. I can determine which country we are operating from the controllers,models,views,etc but not from the config file. Is there a Ruby meta programming or some other kind of magic that I'm not aware of so that I want to say if we are working on UK as a country in the app, use UK's bucket credentials or Germany as a country, use Germany's bucket credentials? I can't think of a way to pass parameters to environment files from the app itself. Thank you very much in advance for all your helps.
Rather than actually pass the configuration details to whichever S3 client you're using at launch, you should probably select the relevant credentials for each request. Your config file can define them all in a hash like so:
# config/s3.rb
S3_BUCKETS => {
:us => 'our-files-us',
:gb => 'our-files-gb',
:tz => 'special-case'
}
Then you can select the credentials on request like so (in maybe your AppController):
bucket_name = S3_BUCKETS[I18n.locale]
# pass this info to your S3 client
Make sense?
Write a little middleware if you want to keep the knowledge of the per-country configuration out of the main application.
A middleware is extremely simple. A do-nothing middleware looks like this:
class DoesNothing
def initialize(app, *args)
#app = app
end
def call(env)
#app.call(env)
end
end
Rack powers applications through chaining a series of middlewares together... each one is given a reference to #app, which is the next link in the chain, and it must invoke #call on that application. The one at the end of the chain runs the app.
So in your case, you can do some additional configuration in here.
class PerCountryConfiguration
def initialize(app)
#app = app
end
def call(env)
case env["COUNTRY"]
when "AU"
Rails.application.config.s3_buckets = { ... }
when "US"
Rails.application.config.s3_buckets = { ... }
... etc
end
#app.call(env)
end
end
There are several ways to use the middleware, but since it depends on access to the Rails environment, you'll want to do it from inside Rails. Put it in your application.rb:
config.middleware.use PerCountryConfiguration
If you want to pass additional arguments to the constructor of your middleware, just list them after the class name:
config.middleware.use PerCountryConfiguration, :some_argument
You can also mount the middleware from inside of ApplicationController, which means all of the initializers and everything will have already been executed, so it may be too far along the chain.

Resources