Рубин на рельсах
Я пытаюсь подключить StipeConnect к своему приложению. Я скачал простой пример кода с https://github.com/rfunduk/rails-stripe-connect-example Я обновляю и устанавливаю пакет, копирую и изменяю некоторые файлы сеанса, но получаю ошибку:
NameError in Users#show
Showing /home/ppl/rps/09.25/app_simple_alpha/app/views/users/_connect.html.erb where line #18 raised:
uninitialized constant ActionView::CompiledTemplates::StripeStandalone
Extracted source (around line #18):
<small>Create a standalone Stripe account in</small>
<select class="country" name="country">
#error line <% StripeStandalone::COUNTRIES.each do |country| %>
<option value="<%= country[:code] %>">
<%= country[:name] %>
</option>
Trace of template inclusion: app/views/users/show.html.erb
Вот мои файлы:
модели / user.rb
class User < ActiveRecord::Base
attr_accessor :remember_token, :activation_token, :reset_token
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, length: { minimum: 6 }, allow_nil: true
serialize :stripe_account_status, JSON
def connected?; !stripe_user_id.nil?; end
def managed?; stripe_account_type == 'managed'; end
def standalone?; stripe_account_type == 'standalone'; end
def oauth?; stripe_account_type == 'oauth'; end
def manager
case stripe_account_type
when 'managed' then StripeManaged.new(self)
when 'standalone' then StripeStandalone.new(self)
when 'oauth' then StripeOauth.new(self)
end
end
def can_accept_charges?
return true if oauth?
return true if managed? && stripe_account_status['charges_enabled']
return true if standalone? && stripe_account_status['charges_enabled']
return false
end
#...
end
Контроллеры / users_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
before_action :require_user, except: %w{ new create }
require 'will_paginate/array'
def index
@users = User.all.paginate(page: params[:page])
end
# ...
def show
@user = User.find(params[:id])
@plans = Stripe::Plan.all
end
def pay
user = User.find( params[:id] )
amount = 1000
fee = (amount * Rails.application.secrets.fee_percentage).to_i
begin
charge_attrs = {
amount: amount,
currency: user.currency,
source: params[:token],
description: "Test Charge via Stripe Connect",
application_fee: fee
}
case params[:charge_on]
when 'connected'
# Use the user-to-be-paid's access token
# to make the charge directly on their account
charge = Stripe::Charge.create( charge_attrs, user.secret_key )
when 'platform'
# Use the platform's access token, and specify the
# connected account's user id as the destination so that
# the charge is transferred to their account.
charge_attrs[:destination] = user.stripe_user_id
charge = Stripe::Charge.create( charge_attrs )
end
flash[:notice] = "Charged successfully! <a target='_blank' rel='#{params[:charge_on]}-account' href='https://dashboard.stripe.com/test/payments/#{charge.id}'>View in dashboard »</a>"
rescue Stripe::CardError => e
error = e.json_body[:error][:message]
flash[:error] = "Charge failed! #{error}"
end
redirect_to user_path( user )
end
def subscribe
user = User.find( params[:id] )
fee_percent = (Rails.application.secrets.fee_percentage * 100).to_i
begin
customer = Stripe::Customer.create(
{
source: params[:token],
email: current_user.email,
plan: params[:plan],
application_fee_percent: fee_percent
},
user.secret_key
)
flash[:notice] = "Subscribed! <a target='_blank' rel='platform-account' href='https://dashboard.stripe.com/test/customers/#{customer.id}'>View in dashboard »</a>"
rescue Stripe::CardError => e
error = e.json_body[:error][:message]
flash[:error] = "Charge failed! #{error}"
end
redirect_to user_path( user )
end
# ...
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation, :activation_token)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
end
Контроллеры / stripe_controller.rb
class StripeController < ApplicationController
def managed
connector = StripeManaged.new( current_user )
account = connector.create_account!(
params[:country], params[:tos] == 'on', request.remote_ip
)
if account
flash[:notice] = "Managed Stripe account created! <a target='_blank' rel='platform-account' href='https://dashboard.stripe.com/test/applications/users/#{account.id}'>View in dashboard »</a>"
else
flash[:error] = "Unable to create Stripe account!"
end
redirect_to user_path( current_user )
end
def standalone
connector = StripeStandalone.new( current_user )
account = connector.create_account!( params[:country] )
if account
flash[:notice] = "Standalone Stripe account created! <a target='_blank' rel='platform-account' href='https://dashboard.stripe.com/test/applications/users/#{account.id}'>View in dashboard »</a>"
else
flash[:error] = "Unable to create Stripe account!"
end
redirect_to user_path( current_user )
end
def oauth
connector = StripeOauth.new( current_user )
url, error = connector.oauth_url( redirect_uri: stripe_confirm_url )
if url.nil?
flash[:error] = error
redirect_to user_path( current_user )
else
redirect_to url
end
end
def confirm
connector = StripeOauth.new( current_user )
if params[:code]
# If we got a 'code' parameter. Then the
# connection was completed by the user.
connector.verify!( params[:code] )
elsif params[:error]
# If we have an 'error' parameter, it's because the
# user denied the connection request. Other errors
# are handled at #oauth_url generation time.
flash[:error] = "Authorization request denied."
end
redirect_to user_path( current_user )
end
def deauthorize
connector = StripeOauth.new( current_user )
connector.deauthorize!
flash[:notice] = "Account disconnected from Stripe."
redirect_to user_path( current_user )
end
end
Контроллеры /hooks_controller.rb
class HooksController < ApplicationController
skip_before_action :verify_authenticity_token
def stripe
user = params[:user_id] && User.find_by( stripe_user_id: params[:user_id] )
args = [ params[:id], user.try(:secret_key) ].compact
begin
event = Stripe::Event.retrieve( *args )
rescue Stripe::InvalidRequestError
render nothing: true, status: 200
return
rescue Stripe::AuthenticationError
if user && user.connected?
connector = StripeConnect.new( user )
connector.deauthorized
end
render nothing: true, status: 200
return
end
case event.try(:type)
when 'account.application.deauthorized'
if user && user.connected?
user.manager.deauthorized
end
when 'account.updated'
if user && user.connected?
user.manager.update_account!
end
when 'charge.succeeded'
Rails.logger.info "**** STRIPE EVENT **** #{event.type} **** #{event.id}"
when 'invoice.payment_succeeded'
Rails.logger.info "**** STRIPE EVENT **** #{event.type} **** #{event.id}"
when 'invoice.payment_failed'
Rails.logger.info "**** STRIPE EVENT **** #{event.type} **** #{event.id}"
end
render nothing: true, status: 200
end
end
Контроллеры / application_controller.rb
Класс ApplicationController protect_from_forgery with:: исключение def require_user
if session[:user_id].blank?
redirect_to new_sessions_path вернуть конец конец конец хелперы / application_helper.rb активы /javascrips/application.js активы / JavaScript / приложение / connect.coffee активы / JavaScript / приложение /pay.coffee Услуги /stripe_managed.rb Услуги / stripe_standalone.rb просмотров / пользователей / _connect.html.erb просмотров / пользователей / show.html.erb подробнее: https://groups.google.com/forum/ Спасибо за любую помощьmodule ApplicationHelper
def full_title(page_title)
base_title = "GoodApp"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
# # Lookup logged in user from session, if applicable.
#def current_user
# @_current_user ||= User.find_by_id( session[:user_id] )
#end
def is_myself?
@user == current_user
end
end
//= require jquery
//= require jquery_ujs
//= require bootstrap
//= require turbolinks
// require bootstrap-sprockets
//= require app/niceties
//= require app/connect
//= require app/pay
//= require app/subscribe
//= require_tree .
$(document).ready ->
# pre-connection
setupManaged()
setupStandalone()
# connected user, but we need info
setupFieldsNeeded()
setupManaged = ->
container = $('#stripe-managed')
return if container.length == 0
tosEl = container.find('.tos input')
countrySelect = container.find('.country')
form = container.find('form')
createButton = form.find('.btn')
tosEl.change -> createButton.toggleClass 'disabled', !tosEl.is(':checked')
form.submit ( e ) ->
if !tosEl.is(':checked')
e.preventDefault()
return false
createButton.addClass('disabled').val('...')
countrySelect.change ->
termsUrl = "https://stripe.com/#{countrySelect.val().toLowerCase()}/terms"
tosEl.siblings('a').attr( href: termsUrl )
setupStandalone = ->
container = $('#stripe-standalone')
return if container.length == 0
countrySelect = container.find('.country')
form = container.find('form')
createButton = form.find('.btn')
form.submit ( e ) ->
createButton.addClass('disabled').val('...')
setupFieldsNeeded = ->
container = $('.needed')
return if container.length == 0
form = container.find('form')
form.submit ( e ) ->
button = form.find('.buttons .btn')
button.addClass('disabled').val('Saving...')
if (baContainer = form.find('#bank-account')).length > 0
Stripe.setPublishableKey baContainer.data('publishable')
tokenField = form.find('#bank_account_token')
if tokenField.is(':empty')
e.preventDefault()
Stripe.bankAccount.createToken form, ( _, resp ) ->
if resp.error
button.removeClass('disabled').val('Save Info')
alert( resp.error.message )
else
tokenField.val( resp.id )
form.get(0).submit()
return false
assets/javascript/app/niceties.coffee
$(document).ready ->
setTimeout(
-> $('.alert.alert-info.auto').slideUp('fast')
3500
)
$('body').on 'click', 'a[rel=platform-account]', ( e ) ->
return confirm("This link will only work if you're logged in as the **application owner**. Continue?")
$('body').on 'click', 'a[rel=connected-account]', ( e ) ->
return confirm("This link will only work if you're logged in as the **connected account**. Continue?")
$(document).ready ->
return unless StripeCheckout?
submitting = false
payButton = $('.pay-button')
form = payButton.closest('form')
destination = form.find('select[name=charge_on]')
indicator = form.find('.indicator').height( form.outerHeight() )
handler = null
createHandler = ->
handler = StripeCheckout.configure
key: window.publishable[destination.val()]
email: window.currentUserEmail
allowRememberMe: false
closed: ->
form.removeClass('processing') unless submitting
token: ( token ) ->
submitting = true
form.find('input[name=token]').val( token.id )
form.get(0).submit()
destination.change createHandler
createHandler()
payButton.click ( e ) ->
e.preventDefault()
form.addClass( 'processing' )
handler.open
name: 'Rails Connect Example'
description: '$10 w/ 10% fees'
amount: 1000
assets/javascript/app/subscribe.coffee
$(document).ready ->
return unless StripeCheckout?
# Holds the plan selected by the user in the interface.
currentPlan = null
submitting = false
subscribeButton = $('.subscribe-button')
planButtons = $('.plan-choice')
form = subscribeButton.closest('form')
indicator = form.find('.indicator').height( form.outerHeight() )
handler = StripeCheckout.configure
key: window.stripePublishableKey
# The email of the logged in user.
email: window.currentUserEmail
allowRememberMe: false
closed: ->
subscribeButton.attr( disabled: true )
planButtons.removeClass('active')
currentPlan = null
form.removeClass('processing') unless submitting
token: ( token ) ->
submitting = true
form.find('input[name=token]').val( token.id )
form.get(0).submit()
planButtons.click ( e ) ->
e.preventDefault()
planButton = $(this)
planButton.addClass('active').siblings().removeClass('active')
subscribeButton.attr( disabled: false )
currentPlan =
id: planButton.data('id')
name: planButton.data('name')
currency: planButton.data('currency')
amount: parseInt planButton.data('amount'), 10
form.find('input[name=plan]').val( currentPlan.id )
subscribeButton.show()
subscribeButton.click ( e ) ->
e.preventDefault()
form.addClass('processing')
if currentPlan == null
alert "Choose a plan first!"
return
handler.open
name: 'Rails Connect Example'
description: "#{currentPlan.name} Subscription"
amount: currentPlan.amount
class StripeManaged < Struct.new( :user )
ALLOWED = [ 'US', 'CA' ] # public beta
COUNTRIES = [
{ name: 'United States', code: 'US' },
{ name: 'Canada', code: 'CA' },
{ name: 'Australia', code: 'AU' },
{ name: 'United Kingdom', code: 'GB' },
{ name: 'Ireland', code: 'IE' }
]
def create_account!( country, tos_accepted, ip )
return nil unless tos_accepted
return nil unless country.in?( COUNTRIES.map { |c| c[:code] } )
begin
@account = Stripe::Account.create(
managed: true,
country: country,
email: user.email,
tos_acceptance: {
ip: ip,
date: Time.now.to_i
},
legal_entity: {
type: 'individual',
}
)
rescue
nil # TODO: improve
end
if @account
user.update_attributes(
currency: @account.default_currency,
stripe_account_type: 'managed',
stripe_user_id: @account.id,
secret_key: @account.keys.secret,
publishable_key: @account.keys.publishable,
stripe_account_status: account_status
)
end
@account
end
def update_account!( params: nil )
if params
if params[:bank_account_token]
account.bank_account = params[:bank_account_token]
account.save
end
if params[:legal_entity]
params[:legal_entity][:dob] = {
year: params[:legal_entity].delete('dob(1i)'),
month: params[:legal_entity].delete('dob(2i)'),
day: params[:legal_entity].delete('dob(3i)')
}
params[:legal_entity].entries.each do |key, value|
if [ :address, :dob ].include? key.to_sym
value.entries.each do |akey, avalue|
next if avalue.blank?
account.legal_entity[key] ||= {}
account.legal_entity[key][akey] = avalue
end
else
next if value.blank?
account.legal_entity[key] = value
end
end
pa = account.legal_entity['address'].dup.to_h
account.legal_entity['personal_address'] = pa
account.save
end
end
user.update_attributes(
stripe_account_status: account_status
)
end
def legal_entity
account.legal_entity
end
def needs?( field )
user.stripe_account_status['fields_needed'].grep( Regexp.new( /#{field}/i ) ).any?
end
def supported_bank_account_countries
country_codes = case account.country
when 'US' then %w{ US }
when 'CA' then %w{ US CA }
when 'IE', 'UK' then %w{ IE UK US }
when 'AU' then %w{ AU }
end
COUNTRIES.select do |country|
country[:code].in? country_codes
end
end
protected
def account_status
{
details_submitted: account.details_submitted,
charges_enabled: account.charges_enabled,
transfers_enabled: account.transfers_enabled,
fields_needed: account.verification.fields_needed,
due_by: account.verification.due_by
}
end
def account
@account ||= Stripe::Account.retrieve( user.stripe_user_id )
end
end
class StripeStandalone < Struct.new( :user )
COUNTRIES = [
{ name: 'United States', code: 'US' },
{ name: 'Canada', code: 'CA' },
{ name: 'Australia', code: 'AU' },
{ name: 'United Kingdom', code: 'GB' },
{ name: 'Ireland', code: 'IE' }
]
def create_account!( country )
return nil unless country.in?( COUNTRIES.map { |c| c[:code] } )
begin
@account = Stripe::Account.create(
email: user.email,
managed: false,
country: country
)
rescue
nil # TODO: improve
end
if @account
user.update_attributes(
currency: @account.default_currency,
stripe_account_type: 'standalone',
stripe_user_id: @account.id,
secret_key: @account.keys.secret,
publishable_key: @account.keys.publishable,
stripe_account_status: account_status
)
end
@account
end
protected
def account_status
{
details_submitted: account.details_submitted,
charges_enabled: account.charges_enabled,
transfers_enabled: account.transfers_enabled
}
end
def account
@account ||= Stripe::Account.retrieve( user.stripe_user_id )
end
end
<div class="panel panel-primary">
<div class="panel-body">
<h3>Connect</h3>
<p>There are 3 ways to create/connect your Stripe account.</p>
<ul class="list-group">
<li class="list-group-item" id="stripe-oauth">
<a class="pull-right btn btn-lg btn-primary" href="<%= stripe_oauth_path %>">Connect</a>
<h3>OAuth</h3>
<p>Connect or create a Stripe account via OAuth.</p>
</li>
<li class="list-group-item" id="stripe-standalone">
<%= form_tag stripe_standalone_path, method: 'POST' do %>
<input class="pull-right btn btn-lg btn-primary" type="submit" value="Create"></input>
<h3>Standalone</h3>
<p>
<small>Create a standalone Stripe account in</small>
<select class="country" name="country">
<% StripeStandalone::COUNTRIES.each do |country| %>
<option value="<%= country[:code] %>">
<%= country[:name] %>
</option>
<% end %>
</select>
</p>
<% end %>
</li>
<% # managed accounts are in public beta %>
<% # see services/stripe_managed.rb#ALLOWED %>
<% if Stripe::Account.retrieve('self').country.in? StripeManaged::ALLOWED %>
<li class="list-group-item" id="stripe-managed">
<%= form_tag stripe_managed_path, method: 'POST' do %>
<input class="pull-right btn btn-lg disabled btn-primary" type="submit" value="Create"></input>
<h3>Managed</h3>
<p>
<small>Create a managed Stripe account in</small>
<select class="country" name="country">
<% StripeManaged::COUNTRIES.each do |country| %>
<option value="<%= country[:code] %>">
<%= country[:name] %>
</option>
<% end %>
</select>
<br/>
<label class="tos">
<input checked="<%= false %>" name="tos" type="checkbox"></input>
I accept the
<a href="https://stripe.com/us/terms" target="_blank">Stripe Terms of Service</a>
</label>
</p>
<% end %>
</li>
<% end %>
</ul>
</div>
<div class="col-md-6 col-md-offset-3 col-xs-12">
<%= render partial: 'nav' %>
<% if flash[:notice] %>
<div class="alert alert-info">
<p>
<%= flash[:notice].html_safe %>
</p>
</div>
<% end %>
<% if flash[:error] %>
<div class="alert alert-danger">
<p>
<%= flash[:error].html_safe %>
</p>
</div>
<% end %>
<h1>
<%= @user.name %>
</h1>
<h4>
<%= @user.email %>
</h4>
<% if @user.connected? %>
<% if is_myself? %>
<% # you're looking at your own 'profile', so you can %>
<% # update/deauthorize/etc your Stripe account %>
<%= render partial: 'settings' %>
<% else %>
<%= render partial: 'pay' %>
<% end %>
<% else %>
<% if is_myself? && !current_user.connected? %>
<% # you're looking at your own 'profile', so you can %>
<% # create/connect/etc your Stripe account %>
<%= render partial: 'connect' %>
<% else %>
<div class="panel panel-danger not-connected">
<div class="panel-body">
<h3>Not Connected</h3>
<p>
This user is not connected to Stripe, so
you can't pay them.
</p>
</div>
</div>
<% end %>
<% end %>
</div>
1 ответ
Rails не может загрузить StripeStandalone
оказание услуг. Это странно, потому что его имя и путь верны, поэтому Rails должен их автоматически загрузить. Но для этого вам нужно перезапустить Rails после добавления новых сервисов.
Вы также сказали, что используете Spring. Spring позволяет загружать Rails быстрее, предварительно загружая его при первом запуске и сохраняя приложение Rails в фоновом режиме. Так что, если вы используете Spring, после добавления новых сервисов вы должны также перезапустить Spring, выполнив:
spring stop
и снова запустить Rails.
Это должно помочь в вашем случае. Но если нет, то добавьте эту строку в config/application.rb
(внутри class Application < Rails::Application
):
config.autoload_paths << Rails.root.join('app', 'services')
(Надеюсь, вам это не понадобится, поскольку Rails по умолчанию загружает службы)