Kevin K
Kevin K

Reputation: 2227

Regex validation in rails not working: unique, alphanumeric values with blank values allowed

The create and update methods of my controller are not working as expected. One of my attributes is a coupon code. I want the coupon code to be:

Currently, I'm having a few issues. My model is called ClassPrice and it has two attributes: :coupon_code & :cost_in_cents. The issues are:

Here is my controller:

class ClassPrice < ActiveRecord::Base
  has_many :class_section_prices
  has_many :class_sections, through: :class_section_prices
  after_initialize :init

  validates :coupon_code, uniqueness: true, allow_blank: true, allow_nil: true

  validates :coupon_code, format: { with: /\A[A-Z0-9_]+\z/,
    message: "ERROR: only allows upppercase letters, numbers or underscores." }

  def cost_in_dollars
    if self.amount_in_cents == 0 
      "FREE"
    else
      "$#{amount_in_cents / 100.0}0"
    end
  end

  def virtual_price_in_dollars
    amount_in_cents.to_d / 100 if amount_in_cents
  end

  def virtual_price_in_dollars=(dollars)
    self.amount_in_cents = dollars.to_d * 100 if dollars.present?
  end

  private

  def init
    self.coupon_code      ||= ""
    self.amount_in_cents  ||= 0
  end
end

And here is my model:

class Admin::ClassPricesController < ApplicationController
  layout 'admin'
  before_action :full_authenticate

  def full_authenticate
    authenticate_user!
    if !current_user.is_admin?
      flash[:alert] = "Access denied."
      redirect_to root_url
    end
  end

  def index
    @class_prices = ClassPrice.all
  end


  def new
    @class_price = ClassPrice.new
  end

  def create
    if @class_price = ClassPrice.create(class_price_params)
      redirect_to new_admin_class_price_path(@class_price), notice: 'New class price created.'
    else
      render action: "new"
    end
  end

  def edit
    @class_price = ClassPrice.find(params[:id])
  end

  def update
    @class_price = ClassPrice.find(params[:id])
    if @class_price.update_attributes(class_price_params)
      redirect_to edit_admin_class_price_path(@class_price), notice: 'Class Price was successfully updated.'
    else
      render action: "edit"
    end
  end

  def destroy
    @class_price = ClassPrice.find(params[:id])
    if @class_price != nil
      @class_price.destroy
      redirect_to admin_class_prices_path(@class_section), notice: 'Class Price was deleted.'
    else
      redirect_to admin_class_prices_path(@class_section), notice: 'Class Price not found.'
    end
  end

  private

  def class_price_params
    params.require(:class_price).permit(:class_price_id, :amount_in_cents, :coupon_code, :virtual_price_in_dollars)
  end
end

Any idea where the problem is?

Upvotes: 0

Views: 91

Answers (1)

Michał Młoźniak
Michał Młoźniak

Reputation: 5556

There couple of issues that I see in your code:

  1. allow_blank: true will allow value to be nil or empty string, so you don't have to use also allow_nil if you have allow_blank
  2. You are missing allow_blank in format validation.
  3. Get rid of after_initialize callback. It is firing up every time you instantiate ClassPrice object. Also when you fetch correct record from database it will have blank coupon_code and amount_in_cents set to 0
  4. Create action is not correct. ClassPrice.create will always return an object no matter if it was saved to the database or not. And this object will always evaluate to true. You should split this into 2 lines, first build an object and the save it.

So your validations should look like this

validates :coupon_code, uniqueness: { allow_blank: true },
  format: { with: /\A[A-Z0-9_]+\z/, message: "ERROR: only allows upppercase letters, numbers or underscores.", allow_blank: true }

And your create action:

def create
  @class_price = ClassPrice.new(class_price_params)
  if @class_price.save
    redirect_to new_admin_class_price_path(@class_price), notice: 'New class price created.'
  else
    render action: "new"
  end
end

I hope I didn't miss anything.

Upvotes: 1

Related Questions