user12882
user12882

Reputation: 4792

How to add custom validation messages depending on other attribute values?

I am using Ruby on Rails 3.2.9 and I am just trying to use the state_machine gem. I have following statements:

# Model class attributes are:
#
# [String]  status
# [Boolean] checkin_1
# [Boolean] checkin_2
#
class Article < ActiveRecord::Base
  state_machine :attribute => :status, :initial => :unconfirmed do
    state :confirmed, :value => 'confirmed'
    state :unconfirmed, :value => 'unconfirmed'

    event :confirm do
      transition :unconfirmed => :confirmed
    end

    event :unconfirm do
      transition :confirmed => :unconfirmed
    end
  end
end

I would like to add custom validation messages to instance objects (avoiding to save those objects) when the confirm event is triggered and checkin_1 and / or checkin_2 values are false. That is, given I am trying to confirm each of the following objects:

<#Article id: 1, :status: 'unconfirmed', checkin_1: false, checkin_2: false>
<#Article id: 1, :status: 'unconfirmed', checkin_1: false, checkin_2: true>
<#Article id: 1, :status: 'unconfirmed', checkin_1: true, checkin_2: false>

then I would like to avoid to save objects and to add respectively error messages as-like the following:

"can not be confirmed if it is not checked for 1 and 2"
"can not be confirmed if it is not checked for 1"
"can not be confirmed if it is not checked for 2"

How should I make that?

Upvotes: 4

Views: 276

Answers (2)

Raghvendra Parashar
Raghvendra Parashar

Reputation: 4053

    class Article < ActiveRecord::Base
      attr_accessor :checkin_1
      attr_accessor :checkin_2

      state_machine :attribute => :status, :initial => :unconfirmed do
        state :confirmed, :value => 'confirmed'
        state :unconfirmed, :value => 'unconfirmed'

        before_transition any => :confirm do |article|
          return false unless article.custom_validate?
        end

        event :confirm do
          transition :unconfirmed => :confirmed
        end

        event :unconfirm do
          transition :confirmed => :unconfirmed
        end
      end

      private

      def custom_validate?
        validate_flag = true

        if self.checkin_1 and self.checkin_2
          msg = "can not be confirmed if it is not checked for 1 and 2"
          errors.add(:checkin_1, msg)
          errors.add(:checkin_2, msg)
          validate_flag = false
        elsif !checkin_1
          errors.add(:checkin_1, "can not be confirmed if it is not checked for 1")
          validate_flag = false
        elsif !checkin_2
          errors.add(:checkin_2, "can not be confirmed if it is not checked for 2")
          validate_flag = false
        end

        validate_flag
      end
    end

Upvotes: 0

Yanhao
Yanhao

Reputation: 5294

How about doing it like this:

state confirmed do
  validate do
    if !checkin_1 and !checkin_2
       msg = "can not be confirmed if it is not checked for 1 and 2"
       errors.add(:checkin_1, msg)
       errors.add(:checkin_2, msg)
    elsif !checkin_1
       errors.add(:checkin_1, "can not be confirmed if it is not checked for 1")
    elsif !checkin_2
       errors.add(:checkin_2, "can not be confirmed if it is not checked for 2")
    end
  end
end

Upvotes: 1

Related Questions