paypal recurring gem & trial period - ruby-on-rails

I implemented paypal recurring by following Rails Casts EP289. http://railscasts.com/episodes/289-paypal-recurring-billing?view=asciicast
It works fine for normal process, but when I tried to implement trial period, I got some problem. It charges the sum of trial amount and recurring billing amount at the first billing.
(I only want to charge trial amount)
I checked through internet, but I can't figure out how to do that so far.
What am I missing about implementing this correctly?
Below is the code.
paypal_payment.rb
class PaypalPayment
def initialize(subscription)
#subscription = subscription
#price = Price.find_by_currency_code_and_plan_id("JPY", #subscription.plan.id)
end
def checkout_details
PayPal::Recurring.new(token: #subscription.paypal_payment_token).checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.now + 1.month
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_customer_token,
item_name: #subscription.plan.name,
item_amount: #price.amount.to_i,
description: "Something"
amount: #price.amount.to_i,
outstanding: :next_billing,
trial_amount: #price.initial_amount.to_i,
trial_period: :monthly,
trial_frequency: 1,
trial_length: 1,
currency: #price.currency_code,
locale: "ja_JP"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
subscription.rb
class Subscription < ActiveRecord::Base
belongs_to :plan
belongs_to :student
has_many :transactions, :class_name => "SubscriptionTransaction"
validates_presence_of :plan_id
validates_presence_of :student_id
attr_accessor :paypal_payment_token
attr_accessible :paypal_customer_token, :paypal_recurring_profile_token, :plan_id, :student_id, :paypal_payment_token
def save_with_payment
if valid?
if payment_provided?
save_with_paypal_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def payment_provided?
paypal_payment_token.present?
end
end
subscriptions_controller.rb
require 'time'
class SubscriptionsController < ApplicationController
before_filter :authenticate_user!, :is_student?
def index
#title = I18n.t "subscriptions.index.title"
#student = Student.find_by_id(current_user.profile_id)
if #student.is_trial == true
redirect_to 'new'
end
#subscription = #student.subscription
#plan = #subscription.plan
Time.zone = "Tokyo"
#date = Time.now.in_time_zone.to_date
#total_lesson_times = Lesson.find_all_by_student_id(#student.id).size
#lastm_lesson_times = Lesson.where("student_id = :student_id AND lesson_day >= :start_date AND lesson_day <= :end_date",
{:student_id => #student.id, :start_date => #date.beginning_of_month()-1.month, :end_date => #date.end_of_month()-1.month}).size
#thism_lesson_times = Lesson.where("student_id = :student_id AND lesson_day >= :start_date AND lesson_day <= :end_date",
{:student_id => #student.id, :start_date => #date.beginning_of_month(), :end_date => #date.end_of_month()}).size
end
def new
#title = I18n.t "subscriptions.new.title"
#plans = Plan.all
#student = Student.find_by_id(current_user.profile_id)
if #student.is_trial == false && #student.is_active == false
redirect_to 'index'
end
#subscription = Subscription.new
#date = Time.now.in_time_zone.to_date
#total_lesson_times = Lesson.find_all_by_student_id(#student.id).size
#lastm_lesson_times = Lesson.where("student_id = :student_id AND lesson_day >= :start_date AND lesson_day <= :end_date",
{:student_id => #student.id, :start_date => #date.beginning_of_month()-1.month, :end_date => #date.end_of_month()-1.month}).size
#thism_lesson_times = Lesson.where("student_id = :student_id AND lesson_day >= :start_date AND lesson_day <= :end_date",
{:student_id => #student.id, :start_date => #date.beginning_of_month(), :end_date => #date.end_of_month()}).size
end
def modify
end
def cancel
student = Student.find(current_user.profile_id)
#subscription = student.subscription
ppr = PayPal::Recurring.new(:profile_id => #subscription.paypal_recurring_profile_token)
response = ppr.suspend
if response.success?
student.update_attributes(:is_active => false)
flash[:notice] = I18n.t "subscriptions.cancel.notice_flash"
redirect_to root_path
end
end
def reactivate
student = Student.find_by_id(current_user.profile_id)
#subscription = student.subscription
ppr = PayPal::Recurring.new(:profile_id => #subscription.paypal_recurring_profile_token)
response = ppr.reactivate
if response.success?
student.update_attributes(:is_active => true)
flash[:success] = I18n.t "subscriptions.reactivate.success_flash"
redirect_to root_path
end
end
def paypal_checkout
plan = Plan.find(params[:plan_id])
student = Student.find(current_user.profile_id)
subscription = plan.subscriptions.build
redirect_to subscription.paypal.checkout_url(
return_url: subscriptions_confirm_url(:plan_id => plan.id),
cancel_url: new_subscription_url
)
end
def confirm
#plan = Plan.find(params[:plan_id])
#student = Student.find(current_user.profile_id)
#subscription = #plan.subscriptions.build
if params[:PayerID]
#subscription.student_id = #student.id
#subscription.paypal_customer_token = params[:PayerID]
#subscription.paypal_payment_token = params[:token]
end
end
def complete
student = Student.find(current_user.profile_id)
Time.zone = student.user.time_zone
current_time = Time.now.in_time_zone
current_date = current_time.to_date
#subscription = Subscription.new(
:plan_id => params[:subscription][:plan_id],
:student_id => params[:subscription][:student_id],
:paypal_customer_token => params[:subscription][:paypal_customer_token],
:paypal_payment_token => params[:subscription][:paypal_payment_token]
)
if #subscription.save_with_payment
student.update_attributes(:is_active => true, :is_trial => false, :expiration_date => current_date + 1.month - 1.day)
redirect_to root_path, :notice => (I18n.t "subscriptions.complete.success_flash")
else
flash[:notice] = I18n.t "error_flash"
redirect_to new_subscription_path
end
end
private
def is_student?
if current_user.profile_type != "Student"
flash[:notice] = I18n.t "is_student_notice_flash"
redirect_to root_path
end
end
end

(Answered in a question edit. Converted to a community wiki answer. See What is the appropriate action when the answer to a question is added to the question itself? )
The OP wrote:
I solved the problem myself. The problem was inside the paypal_payment.rb
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.now + 1.month
end
because of the process :request_payment part. It charges the amount to the user beside of the charge of recurring payment.

Related

undefined method `paypal_url' for nil:NilClass

I have a model class page.rb:
class Page < ActiveRecord::Base
def paypal_url(return_url)
values = {
:business => 'seller_1229899173_biz#railscasts.com',
:cmd => '_cart',
:upload => 1,
:return => return_url,
:invoice => id
}
line_items.each_with_index do |item, index|
values.merge!({
"amount_#{index+1}" => item.unit_price,
"item_name_#{index+1}" => item.product.name,
"item_number_#{index+1}" => item.id,
"quantity_#{index+1}" => item.quantity
})
end
"https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query
end
end
And in my controller:
def order_form
if params[:commit] == "Proceed to Checkout"
redirect_to(#cart.paypal_url("/pages/order_online"))
end
but when I click on "Proceed to Checkout", it gives me an error:
undefined method `paypal_url' for nil:NilClass
Any idea if I'm missing anything or doing anything wrong?
Thanks!
The simple answer is your #cart variable is not being populated with any data
The way to fix this is to create a #cart variable in your order_form controller, like so:
def order_form
#cart = Cart.new cart_params #-> how to define your cart var?
redirect_to #cart.paypal_url "/pages/order_online"
end
I looked at the Railscast you've been using, and it seems he's continuing on from another episode, where he explains how to create the cart object using standard ActiveRecord
A longer answer is that I believe your system is flawed, in that you're calling PayPal methods in your Page model (why?)
We've set up our own cart in Rails before (you can see here):
Cart session model #-> stores product id's in a cart model
Product model stores the products & links with cart id's
Order controller sends data to Paypal & handles returns
Here's some code for you:
#config/routes.rb
get 'cart' => 'cart#index', :as => 'cart_index'
post 'cart/add/:id' => 'cart#add', :as => 'cart_add'
delete 'cart/remove(/:id(/:all))' => 'cart#delete', :as => 'cart_delete'
get 'checkout/paypal' => 'orders#paypal_express', :as => 'checkout'
get 'checkout/paypal/go' => 'orders#create_payment', :as => 'go_paypal'
get 'checkout/stripe' => 'orders#stripe', :as => 'stripe'
#app/models/cart_session.rb #-> "session based model"
class CartSession
#Initalize Cart Session
def initialize(session)
#session = session
#session[:cart] ||= {}
end
#Cart Count
def cart_count
if (#session[:cart][:products] && #session[:cart][:products] != {})
#session[:cart][:products].count
else
0
end
end
#Cart Contents
def cart_contents
products = #session[:cart][:products]
if (products && products != {})
#Determine Quantities
quantities = Hash[products.uniq.map {|i| [i, products.count(i)]}]
#Get products from DB
products_array = Product.find(products.uniq)
#Create Qty Array
products_new = {}
products_array.each{
|a| products_new[a] = {"qty" => quantities[a.id.to_s]}
}
#Output appended
return products_new
end
end
#Qty & Price Count
def subtotal
products = cart_contents
#Get subtotal of the cart items
subtotal = 0
unless products.blank?
products.each do |a|
subtotal += (a[0]["price"].to_f * a[1]["qty"].to_f)
end
end
return subtotal
end
#Build Hash For ActiveMerchant
def build_order
#Take cart objects & add them to items hash
products = cart_contents
#order = []
products.each do |product|
#order << {name: product[0].name, quantity: product[1]["qty"], amount: (product[0].price * 100).to_i }
end
return #order
end
#Build JSON Requests
def build_json
session = #session[:cart][:products]
json = {:subtotal => self.subtotal.to_f.round(2), :qty => self.cart_count, :items => Hash[session.uniq.map {|i| [i, session.count(i)]}]}
return json
end
end
#app/controllers/cart_controller.rb
# shows cart & allows you to click through to "buy"
class CartController < ApplicationController
include ApplicationHelper
#Index
def index
#items = cart_session.cart_contents
#shipping = Shipping.all
end
#Add
def add
session[:cart] ||={}
products = session[:cart][:products]
#If exists, add new, else create new variable
if (products && products != {})
session[:cart][:products] << params[:id]
else
session[:cart][:products] = Array(params[:id])
end
#Handle the request
respond_to do |format|
format.json { render json: cart_session.build_json }
format.html { redirect_to cart_index_path }
end
end
#Delete
def delete
session[:cart] ||={}
products = session[:cart][:products]
id = params[:id]
all = params[:all]
#Is ID present?
unless id.blank?
unless all.blank?
products.delete(params['id'])
else
products.delete_at(products.index(id) || products.length)
end
else
products.delete
end
#Handle the request
respond_to do |format|
format.json { render json: cart_session.build_json }
format.html { redirect_to cart_index_path }
end
end
end
#app/controllers/orders_controller.rb
#Paypal Express
def paypal_express
response = EXPRESS_GATEWAY.setup_purchase(total,
:items => cart_session.build_order,
:subtotal => subtotal,
:shipping => 50,
:handling => 0,
:tax => 0,
:return_url => url_for(:action => 'create_payment'),
:cancel_return_url => url_for(:controller => 'cart', :action => 'index')
)
redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token)
end
#Create Paypal Payment
def create_payment
response = express_purchase
#transactions.create!(:action => "purchase", :amount => ((cart_session.subtotal * 100) + 50).to_i, :response => response)
#cart.update_attribute(:purchased_at, Time.now) if response.success?
response.success?
redirect_to cart_index_path
end
#Stripe
def stripe
credit_card = ActiveMerchant::Billing::CreditCard.new(
:number => "4242424242424242",
:month => "12",
:year => "2020",
:verification_value => "411"
)
purchaseOptions = {
:billing_address => {
:name => "Buyer Name",
:address1 => "Buyer Address Line 1",
:city => "Buyer City",
:state => "Buyer State",
:zip => "Buyer Zip Code"
}
}
response = STRIPE_GATEWAY.purchase(total, credit_card, purchaseOptions)
Rails.logger.debug response.inspect
#responder = response
render cart_index_path
end
private
def subtotal
(cart_session.subtotal * 100).to_i
end
def total
((cart_session.subtotal * 100) + 50).to_i
end
def express_purchase
EXPRESS_GATEWAY.purchase(total, express_purchase_options)
end
def express_purchase_options
{
:token => params[:token],
:payer_id => params[:PayerID]
}
end
def express_token=(token)
self[:express_token] = token
if new_record? && !token.blank?
details = EXPRESS_GATEWAY.details_for(token)
self.express_payer_id = details.payer_id
self.first_name = details.params["first_name"]
self.last_name = details.params["last_name"]
end
end
end

Upgrading subscription plan using paypal recurring gem

I have this setup for Stripe, but I can't seem to figure it out for PayPal recurring gem. I am looking to allow users to switch their payment plan. If user is subscribed to the 1 month subscription (plan_id 1) they should be able to upgrade to year subscription (plan_id 12).
Any help would be appreciated!
Subscriptions Controller
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
if params[:PayerID]
#subscription.paypal_customer_token = params[:PayerID]
#subscription.paypal_payment_token = params[:token]
#subscription.email = #subscription.paypal.checkout_details.email
end
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 show
#subscription = Subscription.find(params[:id])
end
def paypal_checkout
plan = Plan.find(params[:plan_id])
subscription = plan.subscriptions.build
redirect_to subscription.paypal.checkout_url(
return_url: new_subscription_url(:plan_id => plan.id),
cancel_url: root_url
)
end
def updatesubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
if #user.subscription.plan_id == 12
#customer.update_subscription(:plan => "1", :prorate => true)
current_user.subscription.update_attributes(:plan_id => 1)
flash.alert = 'Your subscription has been changed to monthly!'
redirect_to root_url
elsif #user.subscription.plan_id == 1
#customer.update_subscription(:plan => "12", :prorate => true)
current_user.subscription.update_attributes(:plan_id => 12)
current_user.save!
flash.alert = 'Your subscription has been changed to annually!'
redirect_to root_url
end
end
def cancelsubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.cancel_subscription()
current_user.subscription.update_attributes(:cancelled => 1)
current_user.save!
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
def showcard
#user = current_user
Stripe::Customer.retrieve(#user.subscription.stripe_customer_token).cards.all()
end
def changecard
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
card = #customer.cards.create({
:card => #user.subscription.stripe_customer_token
})
#customer.default_card = card
#customer.save
end
def suspend
#user = current_user
#user.subscription.suspend_paypal
current_user.subscription.update_attributes(:cancelled => 1)
flash.alert = 'Billing has been suspended!'
redirect_to root_url
end
def reactivate
#user = current_user
#user.subscription.reactivate_paypal
current_user.subscription.update_attributes(:cancelled => nil)
flash.alert = 'Billing has been activated!'
redirect_to root_url
end
def updatebilling
#user = current_user
customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
customer.cards.retrieve("#{#user.subscription.stripe_card_id}").delete()
customer.cards.create({
card: {
number: params[:user][:scardnumber],
exp_month: params[:user][:sexp_month],
exp_year: params[:user][:sexp_year],
cvc: params[:user][:scvc],
name: params[:user][:sname],
address_line1: params[:user][:sbilling_address1],
address_line2: params[:user][:sbilling_address2],
address_city: params[:user][:saddress_city],
address_zip: params[:user][:saddress_zip],
address_state: params[:user][:saddress_state],
address_country: params[:user][:saddress_country]
}
})
if customer.save!
#user.stripe_card_id = customer.active_card.id
#user.save!
flash.alert = 'Billing information updated successfully!'
redirect_to root_url
else
flash.alert = 'Stripe error'
redirect_to root_url
end
end
end
PayPal Payment model:
def initialize(subscription)
#subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
def reactivate
process :reactivate, :profile_id => #subscription.paypal_recurring_profile_token
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_customer_token,
description: #subscription.plan.name,
amount: #subscription.plan.price,
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
Subscription model:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
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 payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
save
end
def reactivate_paypal
paypal.reactivate
save
end
end
Unfortunately it is not possible to update or change a subscription's term on PayPal. This subscription would have to be cancelled and a new one set up.
API Reference for UpdateRecurringPaymentsProfile
You would need to calculate the prorated difference, and charge them an INITAMT when setting up the new profile, then set the start date for new AMT that is to be collected after their term is up.
Edit: This is assuming you are using this gem. Since I am unable to find anywhere that it tries to do this automatically for you.

Paypal Recurring Gem - suspend payment

I am looking to setup payment suspension for the paypal recurring gem (followed rails cast). I'm not sure if setting up IPN is required as there's no mention of it in the docs for the gem. The code I currently have takes no action.
I defined cancel recurring in the model, though I am not sure how to finish the code as it is hard for me to understand how this all works. This question has been asked by others but there are no answers to it.
If someone has the time to asset me that would be great!
The question is how to suspend/cancel the user recurring payment.
Paypal_payment.rb:
def initialize(subscription)
#subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
private
def process(action, options = {})
options = options.reverse_merge(
token: #subscription.paypal_payment_token,
payer_id: #subscription.paypal_customer_token,
description: #subscription.plan.name,
amount: #subscription.plan.price,
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
Subscriptions controller:
def new
plan = Plan.find(params[:plan_id])
#subscription = plan.subscriptions.build
if params[:PayerID]
#subscription.paypal_customer_token = params[:PayerID]
#subscription.paypal_payment_token = params[:token]
#subscription.email = #subscription.paypal.checkout_details.email
end
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 show
#subscription = Subscription.find(params[:id])
end
def paypal_checkout
plan = Plan.find(params[:plan_id])
subscription = plan.subscriptions.build
redirect_to subscription.paypal.checkout_url(
return_url: new_subscription_url(:plan_id => plan.id),
cancel_url: root_url
)
end
def updatesubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.update_subscription(:plan => "1", :prorate => true)
current_user.save!
flash.alert = 'Your subscription has been updated!'
redirect_to root_url
end
def cancelsubscription
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
#customer.cancel_subscription()
current_user.save!
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
def showcard
#user = current_user
Stripe::Customer.retrieve(#user.subscription.stripe_customer_token).cards.all()
end
def changecard
#user = current_user
#customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
card = #customer.cards.create({
:card => #user.subscription.stripe_customer_token
})
#customer.default_card = card
#customer.save
end
def suspend
#user = current_user
#user.subscription.suspend_paypal
end
def updatebilling
#user = current_user
customer = Stripe::Customer.retrieve(#user.subscription.stripe_customer_token)
customer.cards.retrieve("#{#user.subscription.stripe_card_id}").delete()
customer.cards.create({
card: {
number: params[:user][:scardnumber],
exp_month: params[:user][:sexp_month],
exp_year: params[:user][:sexp_year],
cvc: params[:user][:scvc],
name: params[:user][:sname],
address_line1: params[:user][:sbilling_address1],
address_line2: params[:user][:sbilling_address2],
address_city: params[:user][:saddress_city],
address_zip: params[:user][:saddress_zip],
address_state: params[:user][:saddress_state],
address_country: params[:user][:saddress_country]
}
})
if customer.save!
#user.stripe_card_id = customer.active_card.id
#user.save!
flash.alert = 'Billing information updated successfully!'
redirect_to root_url
else
flash.alert = 'Stripe error'
redirect_to root_url
end
end
end
Subscription Model:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
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 payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
self.status = "canceled"
save
end
end
Routes:
get "subscriptions/cancelsubscription"
get "subscriptions/updatesubscription"
get "subscriptions/changecard"
get "subscriptions/suspend"
get "subscriptions/updatebilling"
resources :charges
resources :subscriptions
resources :plans
get 'paypal/checkout', to: 'subscriptions#paypal_checkout'
View:
<%= link_to "Suspend paypal", subscriptions_suspend_path, :data => { :confirm => "Are you sure?" } %>
This PaypalPayment is a kind of wrapper for the paypal-recurring gem. So all of the methods in this class just prepare and delegate to PayPal::Recurring that's why all of the methods just call the 'process' method which instantiate and pass the action.
So for suspending/cancelling you just need to add a method for each of this actions. As the document states you need to do this for cancel
ppr = PayPal::Recurring.new(:profile_id => "I-VCEL6TRG35CU")
ppr.suspend
So for your PaypalPayment class it would look like this:
def suspend
process :suspend, :profile_id => #subscription.paypal_recurring_profile_token
end
So your model subscription.rb
def suspend_paypal
paypal.suspend
self.status = "canceled"
save
end
And the controller susbcription_controller.rb
def suspend
current_user.suspend_paypal
end
About IPN, I don't think its necessary if the user suspend through your site, but as the user might cancel it directly through paypal you have to handle this case so the User don't stop paying but keep with an active subscription.

Reference message id when submitting form

When users compose a message, how can I setup so that it references the new message_id created for the conversation_id inside the Messages table?
For example User A sends a new message to User B. Message_id 26 is created and the conversation_id will be 26.
show.html.erb:
<h4>Send Message To User</h4>
<p><%= link_to "Message Me", new_user_message_path(#user), :class => "button" %>
new.html.erb:
<%= f.text_field :conversation_id %>
controller:
def index
#messages = Message.scoped
#message = Message.new
if params[:mailbox] == "sent"
#messages = #user.sent_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
elsif params[:mailbox] == "inbox"
#messages = #user.received_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
#elsif params[:mailbox] == "archived"
# #messages = #user.archived_messages
end
if params[:mailbox] == "unread"
#messages = #user.unread_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
end
if params[:mailbox] == "trash"
#messages = #user.deleted_messages.paginate :per_page => 10, :page => params[:page], :order => "created_at DESC"
end
end
def new
#message = Message.new
#message.conversation_id = params[:conversation_id]
end
def create
#message = Message.new(params[:message])
#message.sender_id = #user.id
if #message.save
flash[:notice] = "Message has been sent"
redirect_to user_messages_path(current_user, :mailbox=>:inbox)
else
render :action => :new
end
end
def show
#new_message = Message.new
#message = Message.find(params[:id])
#message.readingmessage if #message.recipient == current_user
end
def reply
#reply_message = Message.new
#message = Message.new
#message.conversation_id = params[:conversation_id]
end
def destroy
#message = Message.find(params[:id])
#message.destroy
flash[:notice] = "Successfully deleted message."
redirect_to user_messages_path(#user, #messages)
end
def delete_multiple
if params[:delete]
params[:delete].each { |id|
#message = Message.find(id)
#message.mark_message_deleted(#message.id,#user.id) unless #message.nil?
}
flash[:notice] = "Messages deleted"
end
redirect_to user_messages_path(#user, #messages)
end
def update
#message = Message.new
if params[:reply_to]
#reply_to = User.find_by_id(params[:reply_to])
unless #reply_to.nil?
#message.recipient_id = #reply_to.id
end
end
end
Model:
class Message < ActiveRecord::Base
attr_accessible :subject, :conversation_id, :body, :parent_id, :sender_id, :recipient_id, :read_at,:sender_deleted,:recipient_deleted
validates_presence_of :subject, :message => "Please enter message title"
has_many :notifications, as: :event
belongs_to :conversation, inverse_of: :messages
belongs_to :user
scope :unread, -> {where('read_at IS NULL')}
scope :not_deleted_by_recipient, where('messages.recipient_deleted IS NULL OR messages.recipient_deleted = ?', false)
scope :not_deleted_by_sender, where('messages.sender_deleted IS NULL OR messages.sender_deleted = ?', false)
belongs_to :sender,
:class_name => 'User',
:foreign_key => 'sender_id'
belongs_to :recipient,
:class_name => 'User',
:foreign_key => 'recipient_id'
after_create :set_converstation_id
def set_conversation_id
update_column :conversation_id, id
end
def reply
new_message.reply_from_user_id = self.id #save the user id of original repost, to keep track of where it originally came from
end
def self.by_date
order("created_at DESC")
end
# marks a message as deleted by either the sender or the recipient, which ever the user that was passed is.
# When both sender and recipient marks it deleted, it is destroyed.
def mark_message_deleted(id,user_id)
self.sender_deleted = true if self.sender_id == user_id
self.recipient_deleted = user_id if self.recipient_id == user_id
(self.sender_deleted > 0 && self.recipient_deleted > 0) ? self.destroy : self.save!
(self.sender_deleted != 0 && self.recipient_deleted != 0)
end
# Read message and if it is read by recipient then mark it is read
def readingmessage
self.read_at ||= Time.now
save
end
# Based on if a message has been read by it's recipient returns true or false.
def read?
self.read_at.nil? ? false : true
end
def self.received_by(user)
where(:recipient_id => user.id)
end
def self.not_recipient_deleted
where("recipient_deleted = ?", false)
end
def self.sent_by(user)
Message.where(:sender_id => user.id)
end
def next(same_recipient = true)
collection = Message.where('id <> ? AND created_at > ?', self.id, self.created_at).order('created_at ASC')
collection.where(recipient_id: self.recipient_id) if same_recipient
collection.first
end
def previous(same_recipient = true)
collection = Message.where('id <> ? AND created_at < ?', self.id, self.created_at).order('created_at DESC')
collection.where(recipient_id: self.recipient_id) if same_recipient
collection.first
end
end
private
def send_notification(message)
message.notifications.create(user: message.recipient)
end
If you don't have separate models for conversations and messages, how will you discriminate between the creation of a message and the creation of a conversation?
You should have a Conversation Model that has_many messages and references both users.
Anyways, what you're asking is to have a conversation_id when creating a brand new message (or conversation)?
You can do this in two ways:
1.- Change
#message.conversation_id = params[:conversation_id]
to
#message.conversation_id = #message.id
And in the view use a hidden_field_tag (or the helper that does that) for your conversation_id
2.- Set this id directly on the create method
#message.conversation_id = #message.id
(is that the behavior you wanted?)
Also, why do you have #new_message and #message?
Update
As said in the comments:
I have this
<%= link_to "Reply", reply_user_messages_path(#message.sender, :conversation_id => #message) %>
<%= link_to "Reply", reply_user_messages_path(#message.sender, :conversation_id => #message.conversation_id) %>
I need to find a way to merge the two of them. One method sets a conversation_id and the other copies it.
Easiest way to do that, one line if:
<%= link_to "Reply", reply_user_messages_path(#message.sender, conversation_id: #message.conversation_id ? #message.conversation_id : #message.id) %>

Rails save draft update in the controller?

I have a model called articles which has a string field that allows users to set their article to draft. When a draft is selected and a user updates the post I would like it to return to the article edit page as if the user selected the published option then I would like for the user to be redirected to the articles index page.
The problem is I cannot get the article to update and redirect back to the post if the draft option is selected. Am I approaching this the wrong way?
Migration file
def change
add_column :articles, :status, :string, default: 'Draft'
end
articles.rb
scope :submitted, lambda { where('status = ?', 2) }
scope :draft, lambda{ where('status = ?', 1) }
def is_draft?
self.draft
end
articles controller
def update
case #article.status
when 1
#article.status = 'Draft'
else 2
#article.status = 'Published'
end
if #article.status == 1
#article = article.find(params[:id])
flash[:notice] = "Successfully Updated" if #article.update_attributes(params[:article])
respond_with(#article, :location => edit_article_path)
else
#article = article.find(params[:id])
flash[:notice] = "Successfully Updated" if #article.update_attributes(params[:article])
respond_with(#article, :location => articles_path)
end
end
If you really want to work with 1/2 values
Model:
STATUS_VALUES = {1 => "Draft", 2 => "Published"}
scope :submitted, lambda { where('status = ?', STATUS_VALUES[2]) }
scope :draft, lambda{ where('status = ?', STATUS_VALUES[1]) }
attr_accessible :_status
after_initialize do
self.draft! if self.new_record? # be draft by default
end
def draft!
self.status = STATUS_VALUES[1]
end
def published!
self.status = STATUS_VALUES[2]
end
def _status
STATUS_VALUES.invert(status)
end
def _status=(value)
case value
when 1, "1" then self.draft!
when 2, "2" then self.published!
else self.draft!
end
end
def draft?
self.status == STATUS_VALUES[1]
end
def published?
self.status == STATUS_VALUES[2]
end
Controller:
def update
#article = article.find(params[:id])
if #article.update_attributes(params[:article])
flash[:notice] = "Successfully Updated"
if #article.draft?
respond_with(#article, :location => edit_article_path)
else
respond_with(#article, :location => articles_path)
end
else
render :action => :edit
end
end
View:
<%= f.check_box(:_status, "Published", 2, 1) %>

Resources