рубин на рельсах полоса подключения

Я пытаюсь подключить 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 &raquo;</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 &raquo;</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 &raquo;</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 &raquo;</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 ‹ActionController :: Base include SessionsHelper include ApplicationHelper

protect_from_forgery с:: exception

def require_user, если сессия [: user_id] .blank? redirect_to new_sessions_path return end end end конец

помощники / application_helper.rb

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

активы / javascrips / application.js

//= 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 .

активы / javascript / приложение / connect.coffee

$(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?")

активы / javascript / приложение / pay.coffee

$(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

услуги / stripe_managed.rb

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

услуги / stripe_standalone.rb

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

просмотры / пользователи / _connect.html.erb

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

просмотры / пользователи / show.html.erb

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

подробнее: https://groups.google.com/forum/#!topic/rubyonrails-talk/BxqBda8LsR0

Спасибо за любую помощь


person anndrew78    schedule 27.12.2015    source источник
comment
Почему все ваши шаблоны в формате erb, а шаблон в репо - в формате haml? Какую версию Ruby on Rails вы используете?   -  person Jeiwan    schedule 28.12.2015
comment
rails 4.2.2 и ruby ​​2.2.1 Оригинальное приложение с использованием haml, мое приложение - erb. Что-то я конвертирую в erb, что-то нет, я добавляю файл haml, чтобы убедиться, что мне ничего не хватает в исходном приложении полосы. Как вы думаете, это может быть причиной ошибки?   -  person anndrew78    schedule 28.12.2015
comment
Нет, мнения не могут быть поводом. Я просто хотел знать, какие изменения вы внесли. Вы добавили в проект Spring? Также попробуйте запустить StripeStandalone в консоли Rails.   -  person Jeiwan    schedule 29.12.2015
comment
Да, гем был установлен. рельсы c: NameError: неинициализированная константа StripeStandalone   -  person anndrew78    schedule 29.12.2015


Ответы (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 по умолчанию автоматически загружает сервисы)

person Jeiwan    schedule 29.12.2015
comment
Не работает. Но в консоли рельсов я обнаружил новую проблему: ›StripeOauth.class TypeError: несоответствие суперкласса для класса StripeOauth - person anndrew78; 31.12.2015
comment
Это означает, что этот класс уже был определен, а затем переопределен в другом месте. Ошибка могла быть вызвана изменением config.autoload_paths, которое я описал в своем ответе. Попробуйте удалить эту строку, остановить пружину, перезапустить консоль Rails и проверить классы StripeOauth и StripeStandalone. - person Jeiwan; 31.12.2015