У меня есть функция регистрации с использованием devise и расширенная регистрация devise с использованием вложенных атрибутов, т.е. я вложил атрибуты класса Payment в класс пользователя. Мой payment.rb
class Payment < ApplicationRecord
attr_accessor :card_number, :card_cvv, :card_expires_month, :card_expires_year #These are actually instance variables
#We cannot access instance variables outside of class so to overcome that we use attr_accessor which is inclusive of attr_reader and attr_writer
belongs_to :user
def self.month_options
Date::MONTHNAMES.compact.each_with_index.map { |name, i| ["#{i+1} - #{name}", i+1]}
end
def self.year_options
(Date.today.year..(Date.today.year+10)).to_a
end
def process_payment
customer = Stripe::Customer.create email: email, card: token
Stripe::Charge.create customer: customer.id,
amount: 1000,
description: 'Premium',
currency: 'usd'
end
end
, а мой user.rb -
class User < ApplicationRecord
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :validatable
has_one :payment
accepts_nested_attributes_for :payment
end
В моем файле application.rb я добавил тег javascript для полосы
<%= javascript_include_tag "https://js.stripe.com/v3/" %>
мой вид т.е. новый. html .erb. есть form_for, в котором я добавил класс «cc», который я позже определил для запуска javascript
<script language="Javascript">
Stripe.setPublishableKey("<%= ENV['STRIPE_TEST_PUBLISHABLE_KEY']%>");
</script>
<h1><%= t('.sign_up') %></h1>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { role: "form", class: 'cc_form' }) do |f| %>
<%= bootstrap_devise_error_messages! %>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, autocomplete: 'current-password', class: 'form-control' %>
<% if @minimum_password_length %>
<small class="form-text text-muted"><%= t('devise.shared.minimum_password_length', count: @minimum_password_length) %></small>
<% end %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: 'current-password', class: 'form-control' %>
</div>
<%= fields_for( :payment ) do |p| %>
<div class="row col-md-12">
<div class="form-group col-md-4 no-left-padding">
<%= p.label :card_number, "Card Number", data: { stripe: 'label'} %>
<%= p.text_field :card_number, class: "form-control", required: true, data: { stripe: 'number'} %>
</div>
<div class="form-group col-md-2">
<%= p.label :card_cvv, "Card CVV", data: { stripe: 'label'} %>
<%= p.text_field :card_cvv, class: "form-control", required: true, data: { stripe: 'cvc'} %>
</div>
<div class="form-group col-md-6">
<div class="col-md-12">
<%= p.label :card_expires, "Card Expires", data: { stripe: 'label'} %>
</div>
<div class="row">
<div class="col-md-3 form-group">
<%= p.select :card_expires_month, options_for_select(Payment.month_options),
{ include_blank: 'Month' },
"data-stripe" => "exp-month",
class: "form-control", required: true %>
</div>
<div class="col-md-3 form-group">
<%= p.select :card_expires_year, options_for_select(Payment.year_options.push),
{ include_blank: 'Year' },
class: "form-control",
"data-stripe" => "exp-year", required: true %>
</div>
</div>
</div>
</div>
<% end %>
<div class="form-group">
<%= f.submit t('.sign_up'), class: 'btn btn-primary' %>
</div>
<% end %>
<%= render 'devise/shared/links' %>
и мой registration_controller.rb, т.е. расширенную регистрацию устройства
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.class.transaction do
resource.save
yield resource if block_given?
if resource.persisted?
@payment = Payment.new({email: params["user"]["email"], token: params[:payment]["token"], user_id: resource.id})
flash[:error]="Please check registration errors" unless @payment.valid?
begin
@payment.process_payment
rescue => exception e
flash[:error]=e.message
resource.destroy
puts 'Payment failed'
render :new and return
end
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up).push(:payment)
end
end
Я сохранил свои учетные данные, т.е. тестовый публикуемый ключ и тестовый секретный ключ полосы в credentials.yml.enc. У меня есть этот пользовательский javascript credit_card_form. js, в котором будет обрабатываться процесс оплаты полосы через это поле класса «cc»
$(document).on('ready turbolinks:load', function() {
var show_error, stripeResponseHandler, submitHandler;
submitHandler = function (event) {
var $form = $(event.target);
$form.find("input[type=submit]").prop("disabled", true);
//If Stripe was initialized correctly this will create a token using the credit card info
if(Stripe){
Stripe.card.createToken($form, stripeResponseHandler);
} else {
show_error("Failed to load credit card processing functionality. Please reload this page in your browser.")
}
return false;
};
$(".cc_form").on('submit', submitHandler);
stripeResponseHandler = function (status, response) {
var token, $form;
$form = $('.cc_form');
if (response.error) {
console.log(response.error.message);
show_error(response.error.message);
$form.find("input[type=submit]").prop("disabled", false);
} else {
token = response.id;
$form.append($("<input type=\"hidden\" name=\"payment[token]\" />").val(token));
$("[data-stripe=number]").remove();
$("[data-stripe=cvc]").remove();
$("[data-stripe=exp-year]").remove();
$("[data-stripe=exp-month]").remove();
$("[data-stripe=label]").remove();
$form.get(0).submit();
}
return false;
};
show_error = function (message) {
if($("#flash-messages").size() < 1){
$('div.container.main div:first').prepend("<div id='flash-messages'></div>")
}
$("#flash-messages").html('<div class="alert alert-warning"><a class="close" data-dismiss="alert">×</a><div id="flash_alert">' + message + '</div></div>');
$('.alert').delay(5000).fadeOut(3000);
return false;
};
});
Итак, этот javascript в основном сначала обращается к серверу rails и сначала обрабатывает полосу оплаты. У меня есть эти два маршрута в моих маршрутах. Rb
devise_for :users , :controller =>{:registrations =>'registrations'}
root to: "welcome#index"
но когда я подписываю Ссылка для подтверждения правильного электронного письма отправлена на мою учетную запись Gmail через sendgrid. но когда я нажимаю эту ссылку подтверждения, локальный хост не отвечает. Я не могу найти ошибку. Пожалуйста, помогите мне.