Paypal IPN on Rails app not being called - ruby-on-rails-3

We are using Paypal Adaptive Chained payments to allow contributions on a crowd funding website. I've got everything working as far as making the payment and being returned to the 'return_url' after a successful payment (in the sandbox).
Paypals documentation on testing IPN in the Sandbox is sparse. Perhaps I missed a setting somewhere to enable IPN callbacks?
I would like to be able to use the IPN callback to verify a successful payment. I would like to see the callback JSON so I know which field to capture and compare with. I have found sample code, but the IPN callback doesn't seem to be called in the Sandbox. I've tried to output the params like so (also the puts statement isn't called):
****backers_controller.rb
class BackersController < ApplicationController
include ActiveMerchant::Billing::Integrations
def callback_ipn
puts "callback: ipn"
notify = PaypalAdaptivePayment::Notification.new(request.raw_post)
puts notify.to_yaml
end
def callback_return
puts "callback: return"
#backer = Backer.find(params[:id])
#reward = #project.rewards.find_by_id(#backer.reward_id)
#backer.callback
respond_to do |format|
format.html { render :layout => 'application_proj_back_blog' }
format.json { render json: #backer }
end
end
(The 'callback_return' action is working)
****backer.rb
class Backer < ActiveRecord::Base
include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
def purchase
project = Project.find(self.project_id)
default_url_options[:host] = 'localhost:3000'
proj_owner_email = User.find(project.user_id).email
recipients = [{:email => PRIMARY_EMAIL,
:amount => total_pledge,
:primary => true},
{:email => project.paypal_email,
:amount => project_owner_cut,
:primary => false}
]
response = GATEWAY.setup_purchase(
:action_type => "PAY_PRIMARY",
:return_url => callback_return_project_backer_url(project, self),
:cancel_url => callback_cancel_project_backer_url(project, self),
:ipn_notification_url => callback_ipn_project_backer_url(project, self),
:currency_code =>"USD",
:receiver_list => recipients
)
puts response.to_yaml
pay_key = response["payKey"]
pledge_transactions.create!(:action => "purchase", :amount => total_pledge, :response => response)
return response["payKey"]
end
Back in backers_controller.rb, 'def purchase' calls the purchase:
****backers_controller.rb
class BackersController < ApplicationController
def purchase
#backer = Backer.find(params[:id])
#backer.purchase
redirect_to (GATEWAY.redirect_url_for(#backer.purchase))
end

It turns out my authentication was preventing paypal from calling my ipn listener.

Related

IPN handling with paypal-recurring gem in Rails

I have tried to figure out this response back to PayPal for a while and it drives me nuts. Somewhere I need to send it back to stop PayPal from re-sending the IPN. This is my code for the IPN listener so far, how do I send the IPN response? Just doing ppr.valid? creates a VERIFIED response but the IPN messages keep coming so I guess that doesn't count as an IPN response. The valid? line always fails as well as it can't find the email and seller_id, which I also need to put somewhere (this stuff needs documentation). See gem documentation here: https://github.com/fnando/paypal-recurring
def ipn
subscription = Subscription.where(:email => params[:payer_email], :status => "Active").last
if subscription
ppr = PayPal::Recurring::Notification.new(params)
PaymentsNotification.create!(:params => params.to_json, :status => params[:payment_status], :transaction_id => params[:txn_id])
if ppr.valid? && (ppr.express_checkout? || ppr.recurring_payment?)
#business logic
end
end
I ended up with this code:
def ipn
subscription = Subscription.where(:email => params[:payer_email], :status => "Active").last
if subscription
PaymentsNotification.create!(:params => params.to_json.gsub("\"", "'"), :status => params[:payment_status], :transaction_id => params[:txn_id])
ppr = PayPal::Recurring::Notification.new(params)
ppr.response #send back the response to confirm IPN, stops further IPN notifications from being sent out
if ppr.verified? && ppr.completed?
if ppr.express_checkout? || ppr.recurring_payment?
#do stuff here
end
else
#raise response.errors.inspect
end
end
render :nothing => true
end

From Rails devise auth to backbone & api?

i want to rebuild an app which is a typical rails 3.2 mvc app into a API + Frontend (Backbone) only. As I have no experience in building APIs in rails including authenticatin:
What's the best way to authenticate with devise using backbone? Using auth_tokens?
How should I make he API? Just printing out JSON or use a gem like Grape?
thanks in advance!
I can explain you the way i do this :
First, i install a standard rails application with devise. After that, i create my own session controller :
class SessionsController < ApplicationController
def authenticate
# this method logs you in and returns you a single_access_token token for authentication.
#user = User.find_for_authentication(:email => params[:user][:email])
if #user && #user.valid_password?(params[:user][:password])
render :json => {:user => {:email => #user.email, :id => #user.id, :firsname => #user.firstname, :lastname => #user.lastname, :team_id => #user.team_id, :singleAccessToken => #user.generate_access_token}}
else
render :json => {:errors => ["Nom d'utilisateur ou mot de passe invalide"]}, :status => 401
end
end
end
As you can see, i send a request to this url with the json looking like :
{
user => {
email => "myemail#toto.com",
password => "monpass"
}
}
And my controller return me the json with user data if every thing is fine, or an error. On json with user, i return an access_token used on next requests to check that the user is allowed to request. I made this filters in my application controller :
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def user_access_token
request.headers["HTTP_X_USER_ACCESS_TOKEN"] || request.headers["HTTP_USER_ACCESS_TOKEN"]
end
def current_user
if token = user_access_token
#user ||= User.find_by_access_token(token)
end
end
def require_user
unless current_user
render :json => {:error => "Invalid Access Token"}, :status => 401
end
end
def require_owner
unless current_user && current_user == object.user
render :json => {:error => "Unauthorized"}
end
end
end
As you can see, on each next request, i will add the access_token in html header on key : HTTP_USER_ACCESS_TOKEN
So, i can check if the user is allowed to make the request.
To make an API, you can use the Rails API gem as see here :
http://railscasts.com/episodes/348-the-rails-api-gem
Good luck.

respond_with location ignored on GET request

At each step in my checkout process, an order is updated via a PUT request. However, one of the states has a form that submits to a third party which redirects back to my site, calling the update method with GET (no control over this).
Why does my respond_with code appear to be totally ignored and I get a Missing Template checkout/update error? It should be hitting #edit.
CheckoutController.rb
before_filter :load_order
def update
if #order.update_attributes(params[:order])
#order.next
end
respond_with(#order, :location => checkout_state_url(#order.state))
end
routes.rb
match '/checkout/update/:state' => 'checkout#update', :as => :update_checkout
match '/checkout/:state' => 'checkout#edit', :as => :checkout_state
match '/checkout' => 'checkout#edit', :state => 'client_details', :as => :checkout
It looks like respond_with does different things depending upon the HTTP verb and whether the resource has errors. See here and here.
The following code worked for me:
def update
if #order.update_attributes(params[:order]) && #order.next
respond_with(#order) { |format| format.html { redirect_to checkout_state_url(#order.state) } }
else
respond_with(#order) { |format| format.html { render :edit } }
end
end

Rails Devise 2.0 own Log-out action

I use Devise and I want to do my logout action.
What I want to do is, that when I log out, I want to create a own JSON object to return. At this time, after I logt out, I get all my root articles.
How can I write my own destory action like I have found the create action?
class SessionsController < Devise::SessionsController
def create
resource = warden.authenticate!(:scope => resource_name, :recall => :failure)
return sign_in_and_redirect(resource_name, resource)
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
return render :json => {:success => true, :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}
end
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
end
And my Routes in routes.rb
devise_for :users, :controllers => {:session => "sessions"} do
get "/users/sing_out" => "devise/sessions#destroy"
end
this is the destroy method of the sessions-controller.
you should be able to customize it to your needs. i think that it would be wiser to add another action and implementing your custom behavior there, as this will be less likely to cause unexpected errors with upgrading devise in the future.
# DELETE /resource/sign_out
def destroy
redirect_path = after_sign_out_path_for(resource_name)
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message :notice, :signed_out if signed_out
# We actually need to hardcode this as Rails default responder doesn't
# support returning empty response on GET request
respond_to do |format|
format.any(*navigational_formats) { redirect_to redirect_path }
format.all do
method = "to_#{request_format}"
text = {}.respond_to?(method) ? {}.send(method) : ""
render :text => text, :status => :ok
end
end
end

Rails testing: session mechanism creates new cart instead of using fixture

I am new to Rails and am following the 'Agile Web Development with Rails' book. Currently I am testing my cart and line items.
In my fixtures I have 2 line items. I delete one in the test, so one more remains in the cart.
However I think due to my session mechanism the controller now uses a new empty cart instead of the fixture cart. This caused my test to fail.
In my *application_controller.rb*
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
en
In my *line_items_controller.rb* I have:
def destroy
#line_item = LineItem.find(params[:id])
#line_item.destroy
respond_to do |format|
if current_cart.line_items.empty?
format.html { redirect_to(store_url, :notice => 'Your cart is empty') }
else
format.html { redirect_to(current_cart, :notice => 'Item removed' )}
end
format.xml { head :ok }
end
end
And in my *functional\line_items_controller_test.rb* I have:
test "should destroy line_item" do
assert_difference('LineItem.count', -1) do
delete :destroy, :id => #line_item.to_param
end
assert(!#cart.line_items.empty?,'Cart should not be empty')
if #cart.line_items.empty?
assert_redirected_to store_url #this was the redirection result
else
assert_redirected_to cart_path(#cart.id) #but should be this redirection
end
end
The code works in real environment, just that the test fails.
How can I modify my test & code, so fixture-cart and my session mechanism can work together and pass the test?
The controller action takes a second hash of session variables to use for the request.
delete :destroy, { :id => #line_item.to_param }, { :cart_id => #cart.id }