I have really been scratching my head on this and would greatly appreciate help. I have a store setup where people can take courses. I have a course model, order model, and coupon model. Here are the associations in the models
class Course < ActiveRecord::Base
belongs_to :category
has_many :orders
has_many :coupons
end
class Order < ActiveRecord::Base
belongs_to :course
belongs_to :user
belongs_to :coupon
end
class Coupon < ActiveRecord::Base
belongs_to :course
has_many :orders
end
I have a very simple coupon model setup that has code and newprice columns. I want the ability for someone to be able to fill out the coupon form on the new order page and it to update the price.
In my my view for new order I have two forms one for the new order and one for the coupon. How do check in my controller if a user has entered the correct coupon code? How do I update the coupon price to be shown instead of the course price?
here is my order controller
class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
@orders = Order.all
end
def show
end
def new
course = Course.find(params[:course_id])
@course = Course.find(params[:course_id])
@order = course.orders.build
@coupon = Coupon.new
@user = current_user.id
@useremail = current_user.email
end
def discount
course = Course.find(params[:course_id])
@order = course.orders.build
@user = current_user.id
@useremail = current_user.email
end
def edit
end
def create
@order = current_user.orders.build(order_params)
if current_user.stripe_customer_id.present?
if @order.pay_with_current_card
redirect_to @order.course, notice: 'You have successfully purchased the course'
else
render action: 'new'
end
else
if @order.save_with_payment
redirect_to @order.course, notice: 'You have successfully purchased the course'
else
render action: 'new'
end
end
end
def update
if @order.update(order_params)
redirect_to @order, notice: 'Order was successfully updated.'
else
render action: 'edit'
end
end
def destroy
@order.destroy
redirect_to orders_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
@order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:course_id, :user_id, :stripe_card_token, :email)
end
end
You can accomplish this with an AJAX request using the
form_for
helper with the:remote
option.Summary
:remote
option totrue
for yourcoupons
form to submit the AJAX request.orders
form (the other form in your view) with the new price information, etc.AJAX request using `:remote`
Here's some example code representing your
coupon
form :Notice the following:
:remote
option for theform_for
tag is set totrue
.:url
option is the path to your controller action in yourCouponsController
. Because the:remote
option is set totrue
, the request will be posted to this:url
option as an AJAX request.routes.rb
file to handle the AJAX request for checking the coupon code:post 'check_coupon_code' => 'coupons#check_coupon_code'
forms_for
helper, the:url
option appends_path
to the prefix defined in theroutes.rb
file.rake routes
to see the available routes and their respective controller action targets.Handle AJAX request in the Controller
In your
CouponsController
, define the actioncheck_coupon_code
to handle your AJAX request from the aboveform_for
:Notice the
format.js
in therespond_to
block of the action. This allows the controller to respond to the AJAX request with JavaScript to update yourorders
form in your view. You'll have to define a correspondingapp/views/coupons/check_coupon_code.js.erb
view file that generates the actual JavaScript code that will be sent and executed on the client side (or name the JavaScript filecheck_coupon_code.js.coffee
if you're using CoffeeScript).Updating with JavaScript
The JavaScript in your
check_coupon_code.js.erb
file will then update the price in yourorder
form.WARNING: Even if you use JavaScript to change the order price on the client-side (i.e. the browser), it is critical to validate the actual price again in the back-end (i.e. in your controller) in case some malicious user tries to manipulate the browser's request, etc.
You can see the official RailsGuide for another example.