<file_sep>class ReservationsController < ApplicationController
  
  before_action :authenticate_user!
  
  def index
    @reservations = Reservation.where status: 'active'
  end
  
  def show
    get_reservation
  end
  
  def new
    @reservation = Reservation.new
  end
  
  def create
    @reservation = Reservation.new reservation_params
 
    if @reservation.save
      redirect_to reservations_path
    else
      render 'new'
    end
  end
  
  def edit
    get_reservation
  end
  
  def update
    get_reservation
    
    if @reservation.update(reservation_params)
      redirect_to @reservation
    else
      render 'edit'
    end
  end
  
  def destroy
    get_reservation
    @reservation.status = 'deleted'
    @reservation.save
 
    redirect_to reservations_path
  end
  
  private
  
  def get_reservation
    @reservation = Reservation.find(params[:id])
  end
  
  def reservation_params
    params.require(:reservation).permit(:scheduled_cruise_id, :name, :address_line_1, :phone, :email, :coupon_code, :additional_information, :passengers_adults, :passengers_seniors, :passengers_kids, :passengers_babies)
  end
end
<file_sep>class ScheduledCruisesController < ApplicationController
  
  before_action :authenticate_user!
  
  def index
    @scheduled_cruises = ScheduledCruise.all
  end

  def new
    @scheduled_cruise = ScheduledCruise.new
  end
      
  def create
    @scheduled_cruise = ScheduledCruise.new (scheduled_cruise_params)
 
    if @scheduled_cruise.save
      redirect_to scheduled_cruises_path
      #render text: params.inspect
    else
      render 'new'
    end
  end
  
  def show
    @scheduled_cruise = ScheduledCruise.find(params[:id])
  end
  
  def edit
    @scheduled_cruise = ScheduledCruise.find(params[:id])
  end
     
  def update
    @scheduled_cruise = ScheduledCruise.find(params[:id])
 
    if @scheduled_cruise.update(scheduled_cruise_params)
      redirect_to @scheduled_cruise
    else
      render 'edit'
    end
  end
  
  def destroy
    @scheduled_cruise = ScheduledCruise.find(params[:id])
    @scheduled_cruise.status = 'deleted'
    @scheduled_cruise.save
 
    redirect_to scheduled_cruises_path
  end
 
  
private

  def scheduled_cruise_params
    result = params.require(:scheduled_cruise).permit(:cruise_type_id, :datetime)
    result[:datetime] = Chronic.parse(result[:datetime])
    
    result
  end
end
<file_sep>class CruiseTypesController < ApplicationController
  
  before_action :authenticate_user!
  
  def index
    @cruise_types = CruiseType.all
  end

  def new
    @cruise_type = CruiseType.new
  end
      
  def create
    @cruise_type = CruiseType.new (cruise_type_params)
 
    if @cruise_type.save
      redirect_to cruise_types_path
    else
      render 'new'
    end
  end
  
  def show
    @cruise_type = CruiseType.find(params[:id])
  end
  
  def edit
    @cruise_type = CruiseType.find(params[:id])
  end
     
  def update
    @cruise_type = CruiseType.find(params[:id])
 
    if @cruise_type.update(cruise_type_params)
      redirect_to cruise_types_path
    else
      render 'edit'
    end
  end
  
  def destroy
    @cruise_type = CruiseType.find(params[:id])
    @cruise_type.status = 'deleted'
    @cruise_type.save
 
    redirect_to cruise_types_path
  end
 
  
private

  def cruise_type_params
    params.require(:cruise_type).permit(:name, :capacity)
  end
    
end
<file_sep>class CruiseType < ActiveRecord::Base
  has_many :scheduled_cruises
  
  validates :name, length: { minimum: 5 }
  validate :validate_capacity
  
  # default_scope { where status: 'active' }
  
  private
  
  def validate_capacity
    if not (capacity and capacity > 0)
      errors.add(:capacity, "should be at least 1")
    end
  end
  
end
<file_sep>class ScheduledCruise < ActiveRecord::Base
  belongs_to :cruise_type
  has_many :reservations, -> { where status: 'active' }
  
  validates :cruise_type, presence: true
  validates :datetime, presence: true
  
  # default_scope { where status: 'active' }
  default_scope { order 'datetime ASC' }
  
  def datetime_pretty
    self.datetime.strftime '%A, %b %d at %l:%M %p'
  end
  
  def description_pretty
    # self.cruise_type.name + ': ' + datetime_pretty
    datetime_pretty + '—' + self.cruise_type.name
  end
  
  def booked_seats
    seats = 0
    reservations.each do |r|
      seats = seats + r.passengers_total
    end
    seats
  end
  
  def available_seats
    self.cruise_type.capacity - booked_seats
  end
    
  #TODO add time zone support
  #TODO only show cruises with enough seats - do this in controller
  def self.available(seats = 1)
    cruises = ScheduledCruise.where("datetime >= ?", Time.now)
    
    cruises.select do |c|
      c.available_seats >= seats
    end
  end
  
end
<file_sep>class AddStatusAttribute < ActiveRecord::Migration
  def change
    change_table :reservations do |t|
      t.string :status
    end
    change_table :cruise_types do |t|
      t.string :status
    end
    change_table :scheduled_cruises do |t|
      t.string :status
    end
  end
end
<file_sep>class ReserveController < ApplicationController
  include Wicked::Wizard
  
  steps :passengers, :cruise, :customer, :confirmation
  
  def reset
    new_reservation
    redirect_to wizard_path steps.first
  end
  
  def show
    find_or_create_reservation
    
    render_wizard
  end
  
  def update
    find_or_create_reservation
    
    @reservation.status = if step == :customer
      'active' 
    else
      step.to_s
    end
    @reservation.update reservation_params
            
    render_wizard @reservation, reservation_id: @reservation.id
  end
  
  private
  
  def find_or_create_reservation
    if session[:reservation_id]
      @reservation = Reservation.find session[:reservation_id]
      
      
    else
      new_reservation
    end
    
    @wicked_step = step
    
    @params = params
  end
  
  def new_reservation
    @reservation = Reservation.create # status: 'new'
    session[:reservation_id] = @reservation.id
  end
  
  def reservation_params
    params.fetch(:reservation, {}).permit(:scheduled_cruise_id, :name, :address_line_1, :phone, :email, :coupon_code, :additional_information, :passengers_adults, :passengers_seniors, :passengers_kids, :passengers_babies)
  end
  
end<file_sep>module ApplicationHelper
  
  def pretty_count(count, none_label = 'none')
    if count.respond_to? :count
      count = count.count
    end
    
    if (not count) or count == 0
      none_label
    else
      count
    end
  end
  
  def relative_datetime(datetime)
    pretty_datetime(datetime)
  end
  
  def pretty_datetime(datetime)
    pretty_date(datetime) + ' at ' + pretty_time(datetime)
  end
  
  def pretty_date(date)
    date.strftime '%A, %b %d'
  end
  
  # FIXME The single-digit hour has a space in front of it. Remove that.
  def pretty_time(time)
    time.strftime '%l:%M %p'
  end
  
  def a_or_an(params_word, uppercase = false)
    if uppercase
      a = "A"
      an = "An"
    else
      a = "a"
      an = "an"
    end
    
    %w(a e i o u).include?(params_word[0].downcase) ? "#{an} #{params_word}" : "#{a} #{params_word}"
  end
  
  def collection_radio_group(object, method, collection, value_method, text_method, options = {}, html_options = {})
    Tags::CollectionSelect.new(object, method, self, collection, value_method, text_method, options, html_options).render
  end
  
  
end
<file_sep>class Reservation < ActiveRecord::Base
  include ActionView::Helpers::TextHelper
  
  belongs_to :scheduled_cruise
  
  validate :validate_passenger_count, if: :active_or_passengers?
  
  validates :scheduled_cruise, presence:  { message: 'Please choose a cruise.' }, if: :active_or_cruise?
  
  with_options if: :active_or_customer? do |s|
    s.validates :name, length: { minimum: 5, message: 'Please type your full name.' }
    s.validates :address_line_1, presence: { message: 'Please type your address.' }
    s.validates :phone, presence: { message: 'Please type your phone number.' }
    s.validates :email, presence: { message: 'Please type your email address.' }
  end
    
  # default_scope { where status: 'active' }
  
  def confirmation_number
    id
  end
  
  def passengers_total
    passengers_adults +
    passengers_seniors +
    passengers_kids +
    passengers_babies
  end
  
  private
  
  def active?
    status == 'active'
  end
  
  def active_or_passengers?
    active? or status == 'passengers'
  end
  
  def active_or_cruise?
    active? or status == 'cruise'
  end
  
  def active_or_customer?
    active? or status == 'customer'
  end
  
  def validate_passenger_count
    if passengers_total == 0
      errors.add(:passengers_adults, "You must have at least one passenger.")
    elsif scheduled_cruise
    
      available = scheduled_cruise.available_seats
      
      if passengers_total > scheduled_cruise.available_seats
        word = if available == 1
          'is one seat'
        elsif available > 1
          "are #{available} seats"
        else
          "are no seats"
        end
        
        errors.add(:passengers_adults, "There #{word} remaining on this cruise—please choose a different cruise or reduce the number of passengers.")
      end
      
    end
  end
  
end
