Rails - How to assign booking numbers to events - ruby-on-rails

I'm building an events app using Ruby on Rails. Events can be either free or paid. In each instance I want to be able to assign a unique booking number for users when they book their places on an event.
What do I need to do to ensure both paid and free events are assigned a number in the server and a booking is then confirmed? Is it as simple as adding a booking_number column in my bookings table?
This is my model and controller code -
booking.rb
class Booking < ActiveRecord::Base
belongs_to :event
belongs_to :user
#validates :quantity, presence: true, numericality: { greater_than: 0 }
validates :total_amount, presence: true, numericality: { greater_than: 0 }
validates :quantity, :total_amount, presence: true
def reserve
# Don't process this booking if it isn't valid
self.valid?
# We can always set this, even for free events because their price will be 0.
#self.total_amount = booking.quantity * event.price
# Free events don't need to do anything special
if event.is_free?
save!
# Paid events should charge the customer's card
else
begin
self.total_amount = event.price_pennies * self.quantity
charge = Stripe::Charge.create(
amount: total_amount,
currency: "gbp",
source: stripe_token,
description: "Booking created for amount #{total_amount}")
self.stripe_charge_id = charge.id
save!
rescue Stripe::CardError => e
errors.add(:base, e.message)
false
end
end
#end
end
end
bookings_controller.rb
class BookingsController < ApplicationController
before_action :authenticate_user!
def new
# booking form
# I need to find the event that we're making a booking on
#event = Event.find(params[:event_id])
# and because the event "has_many :bookings"
#booking = #event.bookings.new(quantity: params[:quantity])
# which person is booking the event?
#booking.user = current_user
##total_amount = #event.price * #booking.quantity
end
def create
puts params
# actually process the booking
#event = Event.find(params[:event_id])
#booking = #event.bookings.new(booking_params)
#booking.user = current_user
if
#booking.reserve
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(#event)
else
flash[:error] = "Booking unsuccessful"
render "new"
end
end
private
def booking_params
params.require(:booking).permit(:stripe_token, :quantity, :event_id, :stripe_charge_id, :total_amount)
end
end
This is my views code. There's an if/else statement here depending on whether its a paid event or not. The free events 'booking_id' simply shows as blank at the moment - not sure why.
booking.new.html.erb
<% if #event.is_free? %>
<div class="col-md-6 col-md-offset-3" id="eventshow">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Your Booking Confirmation</h2>
</div>
<div class="panel-body">
<h1>Hi there</h1>
<p>You have placed a booking on <%= #event.title %></p>
<p>Your order number is <%= #booking.booking_id %></p>
<p>We hope you have a wonderful time. Enjoy!</p>
<p>Love from Mama Knows Best</p>
</div>
<div class="panel-footer">
<%= link_to "Home", root_path %>
</div>
</div>
</div>
</div>
<% else %>
<div class="col-md-6 col-md-offset-3" id="eventshow">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Confirm Your Booking</h2>
</div>
<%= simple_form_for [#event, #booking], id: "new_booking" do |form| %>
<div class="calculate-total">
<p>
Confirm number of spaces you wish to book here:
<input type="number" placeholder="1" name="booking[quantity]" min="1" value="1" class="num-spaces">
</p>
<p>
Total Amount
£<span class="total" data-unit-cost="<%= #event.price %>">0</span>
</p>
</div>
<span class="payment-errors"></span>
<div class="form-row">
<label>
<span>Card Number</span>
<input type="text" size="20" data-stripe="number"/>
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<input type="text" size="4" data-stripe="cvc"/>
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text" size="2" data-stripe="exp-month"/>
</label>
<span> / </span>
<input type="text" size="4" data-stripe="exp-year"/>
</div>
</div>
<div class="panel-footer">
<%= form.button :submit %>
</div>
<% end %>
<% end %>
</div>
</div>
</div>

So you can use the SecureRandom Generator like this, and assuming your model is named Booking
### Add this in your model
before_create :add_booking_number
validates_uniqueness_of :add_booking_number
def add_booking_number
begin
self.booking_number = SecureRandom.hex(2).upcase
other_booking = booking_number.find_by(booking_number: self.booking_number)
end while other_booking
end
To use the Moniker "MAMA" you can do
def add_event_ident
self.booking_number = "MAMA" + '- ' + SecureRandom.hex(2).upcase
...
end
the (2) at the end of the .hex controls the length of the generated string (2) will produce 4 random letters. You can find the best length that works for you by going into rails console and playing with it ie.
SecureRandom.hex(4) ...

You can create a new column like booking_id in your booking table and assign a unique random before the booking object is created.
Ref: Source
If you want the random to be human readable, you can try this

Related

RAILS - HOW TO ADD VOTES IN A POLL

I'm new to Rails and I'm using translate to post here.
I'm practicing rails and for that I set up a poll (voting) system.
Until then the voting is working normally, the votes are stored correctly, however, I would like to set up a screen on the frontend to display the result, and that's where I'm having difficulty.
How can I sum the votes from the PollOptions table of the "Votes" column. I would like to display it like this:
name: 10 votes or X% of votes
name: 10 votes or X% of votes
name: 10 votes or X% of votes
As I understand it, I need to create a method in the controller that will do this sum?
Any documentation links/tips, I'd appreciate it.
polls_controller
class PollsController < ApplicationController
def index
#poll = Poll.where(finished_at: nil).last
#poll_options = #poll.poll_options.order :name
end
def vote
#poll_option = PollOption.find params[:poll_option_id]
#poll_option.increment! :votes
respond_to do |format|
format.turbo_stream { render :vote }
end
end
end
model:
poll
class Poll < ApplicationRecord
has_many :poll_options
end
poll_option
class PollOption < ApplicationRecord
belongs_to :poll
end
In this view, I would like to call the result of the vote.
view _poll.html.erb
<div id="poll-container" class="col-lg-8 mx-lg-auto">
<div class="card shadow">
<div class="card-header">
<h2 class="card-title text-center">
<%= #poll.name %>
<p>
<%= #poll_options.pluck(:name).to_sentence(last_word_connector: ' ou ') %>
</h2>
</div>
<div class="card-body">
<div class="d-flex flex-column bd-highlight mb-3">
<% #poll_options.each do |item| %>
<p>
<%= button_to vote_url,
method: :post,
class: "btn btn-outline-secondary",
params: { poll_option_id: item.id } do %>
<h2>
<%= item.name %>
<%= image_tag item.photo, size: "40x40" %>
</h2>
<% end %>
<% end %>
</div>
</div>
</div>
</div>
https://i.stack.imgur.com/JQfQP.png
Thanks in advance for any guidance.
You can use ActiveRecord::Calculations sum (.sum(:votes)) to sum all the rows for the votes column under poll_options.
To find all the votes of a poll you need the following
#poll.poll_options.sum(:votes)
Then to create the % for the PHP for example you could do
total_votes = #poll.poll_options.sum(:votes)
php_votes = #poll.poll_options.where(name: 'PHP').votes
(php_votes / total_votes).to_i * 100

trying to user sting interpolation or another rails resource method to allow controller user.id data to be viewed in a boot strap label

very new and need guidance, I am a very junior dev. Working on my first project: auth. project - that i've been working on for several months. but I am hitting a wall on how to pull my user.id from my User_controller and import or pull that data into my index.html.erb view.
plan is to have "user.id". render on the page with a label field dynamically. So, if a X user signs in, that "user_id" will show on this label form field by default to show X user is signed, and create some logic later to have my controller validate user and allow to prompt a new modal to change password, but when after user is login, and it routes to /dashboard view, For what ever reason, I can't get the user_id to show in my Label >user_id< using from bootstrap. I feel like this might be easy, but I'm not sure I am fully understand how rails can inject that data resource on the page dynamically
I have tried <%= #{:user_id}%>, change the label type id:/user_id with <%= #{:user_id}%>
this is what my user.controller looks like:
class UserController < ApplicationController
def index
# rendering json on page: user data
render json: User.all
end
def create
user = User.new(
first_name: params[:fname],
last_name: params[:lname],
username: params[:username],
password: params[:password],
password_confirmation: params[:password_confirmation]
)
if user.save
session[:user_id] = user.id
flash[:success] = "text"
#redirect_to '/login'
else
flash[:warning] = "text"
#redirect_to 'register'
end
end
def show
# render plain: params[:id]
#render json: userdata[:users].select {|user| user.get_id() == params[:id].to_i}
if User.exists?(params[:id])
render json: User.find(params[:id].to_i)
else
render plain: "that user doesnt exist: #{params[:id]}"
end
end
def validate
puts params
username = params[:username]
exists = User.exists?(username: username)
# puts exists
render json: {"exists": exists, "username": username}
end
end
and this is my html.erb
<% content_for :content do %>
<div class="container">
<div class="row">
<div class="col-12">
<h1 class=display-4>Welcome to your home page </h1>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
<div class="jumbotron">
<p class="lead">needing to change your password - <strong class="text-success">reset your password easy</strong>.</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-12">
<form class="row g-3">
<div class="col-auto">
<label for="username" class="visually-hidden">Example:user_id</label>
<input type="text" readonly class="form-control-plaintext" id="username" value="Helloguy123#">
</div>
<div class="col-auto">
<label for="password" class="visually-hidden">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password">
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary mb-3">Confirm identity</button>
</div>
</form>
<% end %>
<%= render template: "layouts/application" %>

Stripe Elements Charges not associated to Rails5 Devise current_user - Stripe::InvalidRequestError in CheckoutsController#create

I have Stripe integrated with Stripe Gem and I can successfully create charges and a Stripe user; I just can't get the two to have an association. If I associate the :source => params[:stripeToken] the charge goes through, but if I associate it with my user model :source => current_user.stripe_customer, I get a No such token: cus_BX2RXGoOVkpvhL error.
Here are my request parameters when associating with my user model.
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"/KI7rzkJsM2uXIynoZkWKa1L+kNgyVcw+UsqfPNOnLYO3t4vfL+R7Yb4XhonyhwTbqlyWTtgYjey71ZroSmoRA==",
"charge"=>"2200",
"stripeToken"=>"tok_1B9yneHbiQgBeZWGq78mXM2l",
"card_brand"=>"Visa",
"card_exp_month"=>"4",
"card_exp_year"=>"2024",
"card_last4"=>"4242"}
views/donations/show.html.erb
...
<%= link_to 'Confirm Donation', new_checkout_path(charge: #donation.amount), class: 'btn btn-primary' %>
...
views/checkouts/new.html.erb
<section>
<h1>Secure Payment</h1>
<div class="pages-content">
<% if current_user.card_last4? %>
<%= form_tag checkout_path, id: 'existing-card' do %>
<p>Pay with existing card:</p>
<div><strong>Card on file:</strong>
<%= current_user.card_brand %> (**** **** **** <%= current_user.card_last4 %>)
</div>
<div><strong>Expiration:</strong> <%= current_user.card_exp_month %> / <%= current_user.card_exp_year %></div>
<p>or <%= link_to 'add a new card', '#', class: 'show-card-form' %></p>
<%= hidden_field_tag :charge, params[:charge] %>
<input type="submit" class="btn btn-default" value="Submit Payment">
<% end %>
<% end %>
<%= form_tag checkout_path, id: 'payment-form', style: (current_user.card_last4? ? 'display:none' : nil) do %>
<div class="stripe-wrapper">
<div class="form-row">
<label for="card-element">
Enter Your Credit or Debit Card
</label>
<div id="card-element">
<!-- a Stripe Element will be inserted here. -->
</div>
<%= hidden_field_tag :charge, params[:charge] %>
<!-- Used to display Element errors -->
<div id="card-errors" role="alert"></div>
</div>
<button>Submit</button>
</div>
<% end %>
</div>
</section>
models/user.rb
class User < ApplicationRecord
...
def stripe_customer
if stripe_id?
Stripe::Customer.retrieve(stripe_id)
else
stripe_customer = Stripe::Customer.create(email: email)
update(stripe_id: stripe_customer.id)
stripe_customer
end
end
You need to do this instead, if you're charging the Customer by ID:
:customer => current_user.stripe_customer
I had a similar problem once and i remember that it was because my partner was using a different [Publishable key] on Testing mode, So i gave him mine and it worked, I would like you to make sure that the user is already exists on stripe.
I hope this help you.

Stripe iFrame being blocked - rails and stripe

I am making a checkout form with stripe and rails. I have a shop_controller that serves a list of products in the shop#index. Then that leads to the shop#show where the stripe form is located, and users can purchase a product.
Right now when clicking the button to make a purchase (using the fake card stripe gives you), all that happens is the button endlessly spins, and I get the following errors in the console:
GET https://checkout.stripe.com/api/account/lookup?email=MYEMAILADDRESS&key=&locale=en-US 400 (Bad Request)
and
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://localhost:3000" from accessing a frame with origin "https://checkout.stripe.com". The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "https". Protocols must match.
When I am adding my email to the form, I am also getting this error:
The specified value "MYEMAILADDRESS" is not a valid email address.
Here is my set up
routes.rb
resources :shop
shop_controller
class ShopController < ApplicationController
def index
#products = Product.all
end
def show
#product = Product.find(params[:id])
end
def new
end
# the create happens in the show action
def create
#product = Product.find(params[:id])
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #product.price * 100,
:description => #product.description,
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
show.html.erb (where the form is rendered to pay)
<div class='shop-show'>
<div class="container">
<div class="row text-center">
<div class="col-lg-12 col-xs-12">
<h2><%= #product.name %></h2>
<hr class="generic">
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="white_panel">
<%= form_for #product, url: url_for(controller: 'shop', action: 'create' ) do %>
<% if flash[:error].present? %>
<div id="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<script src="http://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="<%= #product.description %>"
data-amount="<%= #product.price * 100 %>"
data-locale="auto"
data-shipping-address=true>
</script>
<% end %>
<img class="img-responsive" width='400' height='250' src="<%= #product.pictures.first.image.url %>">
<h2><%= #product.description %></h2>
</div>
</div>
</div>
</div>
</div>
Has anyone set up this kind of functionality before? This was closely followed using the link provided by stripe: https://stripe.com/docs/checkout/rails. Any help with this set up would be very appreciated. Thanks.
The Checkout ctript tag's URL there needs to be retrieved over HTTPS. Try swapping this:
<script src="http://checkout.stripe.com/checkout.js"
for this:
<script src="https://checkout.stripe.com/checkout.js"

Getting Stripe working in Rails 4

I am trying to set up stripe in rails and I can enter in the credit card info but when it redirects I get the following error:
No route matches [POST] "/enrollment/1"
I am confused because when I rake routes I get:
enrollment_index GET /enrollment(.:format) enrollment#index
POST /enrollment(.:format) enrollment#create
new_enrollment GET /enrollment/new(.:format) enrollment#new
edit_enrollment GET /enrollment/:id/edit(.:format) enrollment#edit
enrollment GET /enrollment/:id(.:format) enrollment#show
PATCH /enrollment/:id(.:format) enrollment#update
PUT /enrollment/:id(.:format) enrollment#update
DELETE /enrollment/:id(.:format) enrollment#destroy
So I am confused why it is trying to post because in my view, I specify that the method should be put:
<div class='container'>
<div class='jumbotron enroll-page'>
<div class='row'>
<h1>Enroll Here</h1>
<%= form_tag enrollment_path(1), :method => :put do %>
<article>
<label class="amount">
<span>Amount: $5.00</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
</div>
</div>
</div>
My controller looks like this:
class EnrollmentController < ApplicationController
before_filter :authenticate_user!, unless: :admin_signed_in?
def new
end
def create
#get credit card details submitted by form
token = params[:stripeToken]
customer = Stripe::Customer.create(
:card => token,
:plan => 3455,
:email => current_user.email
)
current_user.paid = true
current_user.stripeid = customer.id
current_user.save
redirect_to courses_path, :notice => 'Your enrollment is complete!'
end
end
Thanks so much for any help that you can give!
EDIT: I think I have it. Ajay was totally right that this works better if I name the controller "enrollments" instead of enrollment. In the new.html.erb view, it should look like this instead:
<div class='container'>
<div class='jumbotron enroll-page'>
<div class='row'>
<h1>Enroll Here</h1>
<%= form_tag enrollments_path do %>
<article>
<label class="amount">
<span>Amount: $5.00</span>
</label>
</article>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= Rails.configuration.stripe[:publishable_key] %>"
data-description="A month's subscription"
data-amount="500"></script>
<% end %>
</div>
</div>
</div>
check in routes the resource must be enrollments not enrollment
#routes.rb
resources :enrollments
Now when you run
rake routes | grep 'enrollment'
new_enrollment GET /enrollments/new(.:format) enrollments#new
#app/controller/enrollments_controller.rb
class EnrollmentsController < ApplicationController
def new
#enrollment = Enrollment.new
end
def edit
#enrollment = Enrollment.where(id: params[:id]).first
end
def create
#catch your params and do whatever.
end
def update
# catch your params and do your operation.
end
end
Now comes the View :
app/views/enrollments/new.html.erb
<%= render 'form %>
app/views/enrollments/edit.html.erb
<%= render 'form' %>
now in your app/views/enrollments/_form.html.erb
<%= form_tag(#enrollment)do %>
<%= label_tag :amount %>
<%= text_field_tag :amount, 50.00 %>
<%= submit_tag %>
<% end %>
In your console, the log should be something like this :
Started GET "/enrollments/new" for 127.0.0.1 at 2015-01-10 06:18:08 +0530
Processing by EnrollmentsController#new as HTML
This confirms you are hitting the new page not the edit. Check it !
Inspect your form, this should look like this, check it.

Resources