我终于想出了如何使用本教程实现Stripes Monthly Billing。 http://railscasts.com/episodes/288-billing-with-stripe
到目前为止,用户可以创建&使用Stripe删除其订阅。
但是,用户如何在创建订阅后更改其信用卡信息
这是我的评论和问题代码。请帮助新的rails。 :)
CONTROLLER
class SubscriptionsController < ApplicationController
def new
plan = Plan.find(params[:plan_id])
@subscription = plan.subscriptions.build
@subscription.user_id = current_user.id
end
def create
@subscription = Subscription.new(params[:subscription])
if @subscription.save_with_payment
redirect_to @subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
def update
@subscription = current_user.subscription
if @subscription.save
redirect_to edit_subscription_path, :success => 'Updated Card.'
else
flash.alert = 'Unable to update card.'
render :edit
end
end
end
模型
class Subscription < ActiveRecord::Base
attr_accessible :plan_id, :user_id, :email, :stripe_customer_token, :last_4_digits,
:card_token, :card_name, :exp_month, :exp_year, :stripe_card_token
attr_accessor :stripe_card_token
belongs_to :plan
belongs_to :user
def save_with_payment
if valid?
save_with_stripe_payment
end
end
def save_with_stripe_payment
customer = Stripe::Customer.create(card: stripe_card_token, email: email, plan: plan_id, description: "Unlimited Comics")
self.stripe_customer_token = customer.id
self.card_token = customer.cards.data.first["id"]
self.card_name = customer.cards.data.first["type"]
self.exp_month = customer.cards.data.first["exp_month"]
self.exp_year = customer.cards.data.first["exp_year"]
self.last_4_digits = customer.cards.data.first["last4"]
save!
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #{e.message}"
errors.add :base, "There was a problem with your credit card."
false
end
def update_card
customer = Stripe::Customer.retrieve(stripe_customer_token)
card = customer.cards.retrieve(card_token)
*** This Update works, but how do I pass a new Credit Card Number, Expiration Date etc.
card.name = "My new name"
customer.save
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "#{e.message}."
false
end
end
视图
<%= form_for @subscription do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :plan_id %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :stripe_card_token %>
<h4>Change Credit Card</h4>
<div class="field">
<%= label_tag :card_number, "Credit Card Number" %>
<%= text_field_tag :card_number, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_code, "Security Code on Card (CVV)" %>
<%= text_field_tag :card_code, nil, name: nil %>
</div>
<div class="field">
<%= label_tag :card_month, "Card Expiration" %>
<%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
</div>
<%= f.submit "Change Credit Card", :class => "btn btn-primary" %>
<% end %>
路线
App::Application.routes.draw do
resources :subscriptions
end
SCHEMA
create_table "subscriptions", :force => true do |t|
t.integer "plan_id"
t.integer "user_id"
t.string "email"
t.string "card_name"
t.string "exp_month"
t.string "exp_year"
t.string "card_token"
t.string "stripe_customer_token"
t.string "last_4_digits"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
答案 0 :(得分:28)
由于@TimSullivan的说明
,此答案已更新我必须在我的应用中做同样的事情。 Stripe不允许更新卡号。这为您提供了两个选项:1)创建一张新卡并删除原始卡; 2)创建一张新卡,将其设置为default_card并保留原卡。我选择了第二条路线。
以下是我的表现:
<强>模型/ subscriber.rb 强>
def update_card(subscriber, stripe_card_token)
customer = Stripe::Customer.retrieve(subscriber.stripe_customer_token)
card = customer.sources.create(card: stripe_card_token)
card.save
customer.default_source = card.id
customer.save
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while updating card info: #{e.message}"
errors.add :base, "#{e.message}"
false
end
<强>控制器/ subscribers_controller.rb 强>
def edit_card
@subscriber = current_subscriber
end
def update_card
@subscriber = current_subscriber
if @subscriber.update_card(@subscriber, params[:stripe_card_token])
flash[:success] = 'Saved. Your card information has been updated.'
redirect_to @subscriber
else
flash[:warning] = 'Stripe reported an error while updating your card. Please try again.'
redirect_to @subscriber
end
end
<强>视图/订户/ edit_card.html.erb 强>
<%= form_for @subscriber, url: update_card_path, html: { class: 'update_subscriber' } do |f| %>
<div class='form-group'>
<%= label_tag :number, 'Card Number', class: 'col-sm-3 control-label' %>
<div class='col-sm-9'>
<%= text_field_tag :number, nil, class: 'form-control', placeholder: 'We accept Visa, MasterCard, AMEX and Discover' %>
</div>
</div>
<div class='form-group'>
<%= label_tag :cvc, 'Security Code', class: 'col-sm-3 control-label' %>
<div class='col-sm-9'>
<%= text_field_tag :cvc, nil, class: 'form-control', placeholder: 'The code on the back of your card (CVC)' %>
</div>
</div>
<div class='form-group'>
<%= label_tag :exp_month, 'Expiration Date', class: 'col-sm-3 control-label' %>
<div class='col-sm-5'>
<%= select_month nil, { add_month_numbers: true }, { id: 'exp_month', class: 'form-control btm-space' } %>
</div>
<div class='col-sm-4'>
<%= select_year nil, { start_year: Date.today.year, end_year: Date.today.year+15 }, { id: 'exp_year', class: 'form-control btm-space' } %>
</div>
</div>
<div class='form-group'>
<div class='col-sm-4 col-sm-offset-8'>
<%= submit_tag 'Update', class: 'btn btn-success btn-block' %>
</div>
</div>
<%= f.hidden_field :stripe_card_token %>
<% end %>
<强>配置/ routes.rb中强>
match '/edit_card', to: 'subscribers#edit_card', via: 'get'
match '/update_card', to: 'subscribers#update_card', via: 'post'
应用/ JS / update_card.js 强>
var subscription;
jQuery(function() {
Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
return subscription.setUpForm();
});
subscription = {
setUpForm: function() {
return $('.update_subscriber').submit(function() {
$('input[type="submit"]').attr('disabled', true);
if ($('#card_number').length) {
subscription.updateCard();
return false;
} else {
return true;
}
});
},
updateCard: function() {
var card;
card = {
number: $('#card_number').val(),
cvc: $('#card_code').val(),
expMonth: $('#card_month').val(),
expYear: $('#card_year').val()
};
return Stripe.createToken(card, subscription.handleStripeResponse);
},
handleStripeResponse: function(status, response) {
if (status === 200) {
$('#subscriber_stripe_card_token').val(response.id);
return $('.update_subscriber')[0].submit();
} else {
$('#stripe_error').text(response.error.message);
return $('input[type="submit"]').attr('disabled', false);
}
}
};
希望这有帮助。
答案 1 :(得分:16)
此处接受的答案使用非常不安全。它最终绕着Stripe鼓励的安全性运行。您自己的服务器从不获取信用卡详细信息。
您应instead be using Stripe.js to pass the card to Stripe directly(类似于您在链接的Railscast中已经完成的方式)并检索令牌,然后根据令牌创建卡片。
def update_card(subscriber, stripe_token)
customer = Stripe::Customer.retrieve(subscriber.stripe_customer_token)
card = customer.cards.create(card: stripe_token)
card.save
customer.default_card = card.id
customer.save
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while updating card info: #{e.message}"
errors.add :base, "#{e.message}"
false
end
答案 2 :(得分:5)
您可以更新此信用卡详细信息(PHP代码)
创建条带标记并将其转发到服务器,如下所示:
Stripe.setPublishableKey('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
function stripeResponseHandler(status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// response contains id and card, which contains additional card details
var token = response.id;
alert('The Token Is: '+token);
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
jQuery(function($) {
$('#payment-form').submit(function(event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
在服务器中,您可以更新以下详细信息:
$customer_id = trim($_REQUEST['cus_select']);
$query = "SELECT cus_stripe_id FROM customer_details_tbl WHERE id=$customer_id";
$customer_query = mysqli_query($db_conn,$query);
$row_customer = mysqli_fetch_row($customer_query);
$cus_stripe_id = $row_customer[0];
Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
$error = '';
$success = '';
try {
if (!isset($_POST['stripeToken']))
throw new Exception("The Stripe Token was not generated correctly");
$customer = Stripe_Customer::retrieve($cus_stripe_id);
$customer->source = $_POST['stripeToken'];
$customer->save();
echo "Card Details Updated Successfully";
}
catch (Exception $e) {
$error = $e->getMessage();
echo $error;
}
}
就是这样。这将使用新的详细信息覆盖现有卡片。
答案 3 :(得分:2)
2015年2月18日 客户不再返回cards和default_card属性。您现在应该分别使用sources和default_source。 customer.card。*和customer.bank_account。* webhooks现在命名为customer.source。*。如果您只将卡附加到客户(而不是其他类型的支付来源),那么您可以使用与旧的属性完全相同的新属性。如果您有多种类型的支付来源,则源列表包含异构对象,您可以检查每个源的对象属性以确定其格式。较旧的API版本会返回新属性和旧属性。
答案 4 :(得分:1)
所以Stripe的ruby库有update method,你已经有card.name
但是在截止日期你可以使用card.exp_month
和card.exp_year
,请查看update method对于所有论点。
您会注意到它上面没有更新卡号,所以我的建议是让用户创建另一张卡,如果他们想要更改他们的信用卡号,然后更新客户以将该卡作为他们的默认信用卡(查看条纹ruby库文档中的create card和update a customer)。
希望这有帮助
答案 5 :(得分:1)
使用Tim Sullivan建议的Stripe.js。这是他为更新的Stripe API更新的代码。
def update_card(subscriber, stripe_token)
customer = Stripe::Customer.retrieve({CUSTOMER_ID})
card = customer.sources.create(card: params[:stripeToken])
customer.default_source = card.id
customer.save
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while updating card info: #{e.message}"
errors.add :base, "#{e.message}"
false
end