Create order after successful charge using stripe checkout - ruby-on-rails-4

I am using stripe checkout for my payment solution within and e-commerce app. I want to create an order after a successful charge.
At the moment once payment is successful I just change a "success" boolean attribute on the current cart before destroying the cart. I will like to create an order instead so the cart object does not have to deal with this extra responsibility.
My problem is that I do not know where to tell my controller to create an order and how to pass data from the current cart to the order object.
Here is the charges controller setup
class ChargesController < ApplicationController
def new
#user = current_user
#cart = current_cart
#amount = #cart.total_price
end
def create
#amount = #cart.total_price
customer = Stripe::Customer.create(
:email => #user.email,
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => #user.id,
:amount => #amount,
:description => 'Rails Stripe customer',
:currency => 'usd'
)
# this changes the status of the current cart to success
#cart.update_status(current_cart)
session[:cart_id] = nil
redirect_to current_user, notice: 'You placed an order!'
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
end

Related

Why does a POST request, properly routed, throw an "ActionController::InvalidAuthenticityToken" error in Rails and the shopify_app gem

I am getting the following error when making a post request to /locations/1/submit-to-shopify in my app:
ActionController::InvalidAuthenticityToken in LocationsController#submitshopify
You can see the post route in my routes.rb file below.
root 'home#index'
controller :sessions do
get 'login' => :new, :as => :login
post 'login' => :create, :as => :authenticate
get 'auth/shopify/callback' => :callback
get 'logout' => :destroy, :as => :logout
get 'locations/:id' => 'locations#index'
post 'locations/:id/submit-to-shopify' => 'locations#submitshopify'
end
All the other requests work fine. Here is my Locations controller:
class LocationsController < AuthenticatedController
def index
#location_id = params[:id]
#location = Location.find(#location_id)
end
def submitshopify
#location_id = params[:id]
#location = Location.find(#location_id)
#product_handle = params[:product_handle]
#product = ShopifyAPI::Product.find_by handle: #product_handle
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
#location_id = params[:id]
#location = Location.find(#location_id)
#destroy_status = #location.destroy
end
end
If it is of any consequence, I am using the 'shopify_app' gem, which includes 'shopify_api'. I followed all the directions listed for both of those modules, and have successfully authenticated with Shopify in all of the other pages / controllers.
Have you used helpers to create your submission form?
or have you created it manually? If created manually, have you added the
<%= csrf_meta_tags %>
to your form?
check with your firebug if there is an authentication token at the end of the form. Even the view source should show you that.
We should be discarding that anyone is trying to spam using your form by means of a http client like curl without actually being on your site (cross site request forgery)

rails NoMethodError: undefined method `helper_method' for ApplicationHelper:Module

I have followed this tutorial and its working correctly.
[updated after below answer]
I have moved the code to the Application Controller (previously defined as a helper) to determine if the current user is logged in
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
I have created a module to create a client object and make an api call, this functionality may be used by one or more objects so it seemed like a good idea to create it as a module instead of a controller.
require 'base64'
require 'rubygems'
require 'json'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'net/https'
require 'uri'
module GoogleClient
include ApplicationController
PLUS_LOGIN_SCOPE = 'https://www.googleapis.com/auth/plus.login'
# Build the global client
$credentials = Google::APIClient::ClientSecrets.load("#{Rails.root}/config/client_secret_xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com.json")
$authorization = Signet::OAuth2::Client.new(
:authorization_uri => $credentials.authorization_uri,
:token_credential_uri => $credentials.token_credential_uri,
:client_id => $credentials.client_id,
:client_secret => $credentials.client_secret,
:redirect_uri => $credentials.redirect_uris.first,
:scope => PLUS_LOGIN_SCOPE)
$client = Google::APIClient.new(options = {:application_name => 'xxx-xxx-xxx'} )
def GoogleClient.get_people
if current_user
# Authorize the client and construct a Google+ service.
$client.authorization.update_token!(current_user.oauth_token.to_hash)
plus = $client.discovered_api('plus', 'v1')
# Get the list of people as JSON and return it.
response = $client.execute!(plus.people.list,
:collection => 'visible',
:userId => 'me').body
content_type :json
puts response
else
redirect_to root_url
end
end
end
the user model is;
require 'google_client'
class User < ActiveRecord::Base
include GoogleClient
# after_save GoogleClient.connect
def self.from_omniauth(auth)
where(provider: auth["provider"], uid: auth["uid"]).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
testing it in the console results in
2.1.0 :001 > GoogleClient.get_people
NoMethodError: undefined method `helper_method' for ApplicationHelper:Module
Is it possible to call to a helper method in a module? How should I implement this code if a module is incorrect
** update Correct module code but the api request has a redirect uri error ** explained here in this post
"Notice that modules in /lib are not automatically loaded. Instead, you will need to add this line in your config/application.rb file file config block :"
config.autoload_paths += %W(#{config.root}/lib)
User Model
class User < ActiveRecord::Base
include Google::GoogleClient
def self.from_omniauth(auth)
where(provider: auth["provider"], uid: auth["uid"]).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
if current_user
self.get_people()
else
redirect_to root_url
end
end
'lib/google/google_client.rb'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
module Google
module GoogleClient
# Initialize the client.
client = Google::APIClient.new(
:application_name => 'xxx-xxx',
:application_version => '1.0.0'
)
# Initialize Google+ API. Note this will make a request to the
# discovery service every time, so be sure to use serialization
# in your production code. Check the samples for more details.
# Load client secrets from your client_secrets.json.
client_secrets = Google::APIClient::ClientSecrets.load("#{Rails.root}/config/client_secret_XXXXXXXXXXXXXXXXXXXXXXXx.apps.googleusercontent.com.json")
# Run installed application flow. Check the samples for a more
# complete example that saves the credentials between runs.
flow = Google::APIClient::InstalledAppFlow.new(
:client_id => client_secrets.client_id,
:client_secret => client_secrets.client_secret,
:scope => ['https://www.googleapis.com/auth/plus.me']
)
client.authorization = flow.authorize
def get_people
# Make an API call.
result = client.execute(
:api_method => plus.activities.list,
:parameters => {'collection' => 'public', 'userId' => 'me'}
)
puts result.data
end
end
end
Move both of these to ApplicationController:
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
That will give you a current_user method that works in controllers, helpers, and views.

Ruby on Rails 4.0 session[cart_id] = nil

In my process of learning RoR 4.0, I am following a tutorial to build a Rails project where a Cart is being implemented. My problem is that I can't place more than one item on my cart, because when I go back to the main page to select another item, my cart changes its id . I have the cart_id stored on a session variable, on a function on my application controller:
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_cart
if session[cart_id].nil? (*)
puts “ ********************* “ (*)
puts session[cart_id] (*)
end
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
I call this function from this controller as follows:
class LineItemsController < ApplicationController
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to(#line_item.cart,
:notice => 'Line item was successfully created.') }
format.xml { render :xml => #line_item,
:status => :created, :location => #line_item }
else
format.html { render :action => "new" }
format.xml { render :xml => #line_item.errors,
:status => :unprocessable_entity }
end
end
end
I made several testes, added the three lines of code marked as (*) to my current_cart and I notice that every time that #cart = currect_cart is executed on my lineItems Controller, session[cart_id] is nil.
How could this happen? can comeone explain this to me?
Thank you in advance for your help !

'can not touch on a new record object' error in specs

When you upgrade rails 3.2 -> 4.0. Do not pass the tests, and the error is the following:
Failure/Error: post :create, :user => user_params
ActiveRecord::ActiveRecordError:
can not touch on a new record object
As this problem can be solved?
describe "POST create" do
def do_post
User.should_receive(:new).with(HashWithIndifferentAccess.new(user_params)).and_return(user)
binding.pry
post :create, :user => user_params
end
let(:profile_params) { {:first_name => "John", :last_name => "Bobson", :country => "US"} }
let(:user_params) { {:vid => "12345", :username => "johnbobson", :email => "john#example.com", :user_profile_attributes => profile_params} }
let(:user) { User.new(user_params) }
context "user" do
subject { do_post; user }
its(:invited_at) { should == Date.today.to_time.utc }
its(:invitation_code) { should_not be_nil }
end
end
The reason for this method.
def update_last_active_at
current_user.touch(:last_active_at) if current_user
end
That error is coming about most likely because current_user has not been saved in the database. Rails cannot touch a record that hasn't been saved yet.
To verify this, just check if the current user is a new record before trying to touch it.
def update_last_active_at
if !current_user.new_record?
current_user.touch(:last_active_at) if current_user
end
end

Querying Active Records and Foreign Key Help [Rails 4]

I know there are probably many different ways to do this, but using http://guides.rubyonrails.org/active_record_querying.html, I have been unable to find the best way that works for me.
I am making a forum using RoR, and I came across a problem when deleting posts from topics.
Each Topic has many posts. Each post has one topic.
When you post in the topic, it updates the topic table with who last posted and the time. However, when you delete a post, it keeps the old data of the post.
When I delete a post, I need to update the topic table with the previous post's data.
I know after deleting, I need to query all the posts in a topic, find the last one and use its data to update the topic.
How do I do that though?
The Query would be something like
SELECT * FROM posts WHERE (topic_id = topic.id) ORDER BY id DESC
Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
#post = Post.find(params[:id])
end
def create
#post = Post.new(
:content => params[:post][:content],
:topic_id => params[:post][:topic_id],
:user_id => current_user.id)
if #post.save
#topic = Topic.find(#post.topic_id)
#topic.update_attributes(
:last_poster_id => current_user.id,
:last_post_at => Time.now)
flash[:notice] = "Successfully created post."
redirect_to "/topics/#{#post.topic_id}"
else
render :action => 'new'
end
end
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post].permit!)
#topic = Topic.find(#post.topic_id)
#topic.update_attributes(:last_poster_id => current_user.id, :last_post_at => Time.now)
flash[:notice] = "Successfully updated post."
redirect_to #post
else
render :action => 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
**# WHAT QUERY STATEMENT GOES HERE**
#topic.update_attributes(
:last_poster_id => #post.user_id,
:last_post_at => #post.created_at)
redirect_to "/topics/#{#post.topic_id}"
end
end
Try using this code:
def destroy
#post = Post.find(params[:id])
#topic = #post.topic
#post.destroy
last_post = #topic.reload.posts.last
#topic.update_attributes(last_poster_id: last_post.user_id, last_post_at: last_post.created_at)
redirect_to #topic
end