Nick
Nick

Reputation: 3090

Controller method / Javascript that validates coupon code and updates price

I have a checkout page where a visitor can enter a coupon and thereby get a discount. Also I have an actioncode model with all the possible valid actioncodes, which are generated by the admin. One can submit a coupon and then upon pressing a button, it should validate the coupon and if valid automatically update the price. I've tried following the steps in the answer here, but am not completely sure how to do this.

Of course, this should be done in a secure way. My initial plan was through Javascript but the answers here convinced me this should be done in the controller (and possibly use Javascript to update the amount shown on the checkout view?).

How should I adjust the code below to include the coupon and what Javascript should I include? As it is right now, nothing happens when I press the coupon button.


Routes, which on submitting a new user executes def checkout:

post 'signup/register' => 'organizations#checkout', as: 'signup_checkout'

The controller method that saves the new user and generates the view for checkout (payments). It sets various variables for checkout:

  def checkout
    @organization = Organization.new(organizationnew_params)
    if @organization.save
      @organization.members.each do |single_member|
        single_member.send_activation_email
      end
      @actioncode = Actioncode.new
      @amount = 100.00
      @currency = "EUR"
      @description = @organization.id
      @transaction_description = "My description"
      @transaction_type = "S"
      @hash = hash(@description, @amount, @currency, @transaction_type)
      render 'checkout'   # This renders the checkout view.
    else                            
      render 'new_premium'
    end
  end

The form view with the first four lines producing the form for the actioncode/coupon:

<%= form_for @actioncode, method: :post, url: {action: "check_actioncode", :controller => 'actioncodes'}, remote: true do |f| %>
  <%= f.text_field :actioncode, :placeholder => "Enter your coupon" %>
  <%= f.submit "Submit Coupon Code" %>
<% end %>

<form action="https://secure.paylane.com/order/cart.html" method="post" >
  <%= "If you have a coupon, please enter that first. The amount due is #{@currency} #{number_with_precision(@amount, precision: 2)}. The button below will bring you to the secure environment of PayLane where you can select your payment method." %>
  <!-- form adapted from http://devzone.paylane.com/secure-form-guide/implementation/ -->
  <input type="hidden" name="amount" value=@amount />
  <input type="hidden" name="currency" value=@currency />
  <input type="hidden" name="merchant_id" value=PAYLANE_ID />
  <input type="hidden" name="description" value=@description />
  <input type="hidden" name="transaction_description" value=@transaction_description />
  <input type="hidden" name="transaction_type" value=@transaction_type />
  <input type="hidden" name="back_url" value="https://mysite/signup/confirmation" />
  <input type="hidden" name="language" value="en" />
  <input type="hidden" name="hash" value=@hash />
  <input type="hidden" name="customer_email" [email protected] />
  <button type="submit">Pay with PayLane</button>
</form>

Routes, executing on submitting the coupon button:

post 'check_actioncode' => 'actioncodes#check_actioncode'

The controller method executed upon pushing the button for the actioncode/coupon:

def check_actioncode
  @actioncode = Actioncode.where(:actioncode => params[:actioncode][:actioncode]).first
  respond_to do |format|
    unless @actioncode.empty?
      unless @actioncode.price.empty?
        @amount = @actioncode.price     # It it safe this way, or should (part of) the method be private?
        format.js {}             # What should the js file look like to update the values in the checkout view?
        render 'checkout'        # To reload page with the updated price/amount?
      else
        unless @actioncode.discount.empty?
          @amount = @amount * (100 - @actioncode.discount)  # Not sure how to do this. The first @amount should be yhr new amount, while the second @amount should be the initial amount.
          format.js {}
          render 'checkout'
        else
          flash.now[:danger] = "Action code offers no discount"
        end
      end
    else
      flash.now[:danger] = "Action code not found or expired"
    end
  end
end

Removed the initial Javascript code, since answers suggest that is not a safe way to for example update amounts.

Upvotes: 2

Views: 907

Answers (2)

Sunil B N
Sunil B N

Reputation: 4225

Few things to be noted,you would never bring action codes to UI.People will hack this for sure!

function validate(actioncode) {

    //Here make a call to your backend to validate. I RECOMMEND NOT TO DO IT IN UI.
    //Return somevalue
    //if you have the data in UI, you can use if(validActionCodes.indexOf(actioncode))
    if (isActionValid)
        window.alert("Action Code Accepted! Click the Buy Now button to finalize the payment");
    } else {
        window.alert("Sorry, The Action Code you entered is invalid. Please check and try again!");
    }
}

Upvotes: 2

rfinster
rfinster

Reputation: 68

You should never validate critical user-input clientside (in other words here: with javascript), only. It would be a security leak and target for possible code injection attacks. Why don't you just send the form inputs via post to your controller and validate it there with ruby? I think this would be more conform keeping MVC in mind (the view should not talk to the model).

Upvotes: 1

Related Questions