Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3 Validation with Scope Conditions

I have an invoice model with approver_note, po_number and state_id.

I need validations to check:

validates :approver_note, :presence => true, {:scope => state_id == 3}
validates :po_number, :presence => true, {:scope => state_id ==2}

So, if the user selects state_id = 3, he must enter a note. If he selects state_id = 2, he must enter a po_number.

Any assistance would be great... thanks!

like image 723
Katie M Avatar asked Apr 18 '12 19:04

Katie M


People also ask

What is the scope of a validation in rails?

Luckily, Rails has got us covered with a handy feature called validation scopes. The scope option to the Rails uniqueness validation rule allows us to specify additional columns to consider when checking for uniqueness. This rule says that “the name of this project must unique, within the scope of this account”.

How do I check if an object is valid in rails?

To verify whether or not an object is valid, Rails uses the valid? method. You can also use this method on your own. valid? triggers your validations and returns true if no errors were found in the object, and false otherwise. class Person < ActiveRecord::Base validates :name, :presence => true

What are callbacks and observers in rails?

Callbacks and observers allow you to trigger logic before or after an alteration of an object’s state. Before you dive into the detail of validations in Rails, you should understand a bit about how validations fit into the big picture.

Are there any view helpers for validating messages in rails?

Because every application handles this kind of thing differently, Rails does not include any view helpers to help you generate these messages directly. However, due to the rich number of methods Rails gives you to interact with validations in general, you can build your own.


1 Answers

You're looking for the :if option instead of :scope.

validates :approver_note, :presence => true,
  :if => lambda { |invoice| invoice.state_id == 3 }

But since a lambda is a little ugly, I'd probably add a method to encapsulate what you're doing a bit better:

validates :approver_note, :presence => true, :if => :requires_note?
validates :po_number, :presence => true, :if => requires_po_number?

def requires_note?
  state_id == 3
end

def requires_po_number?
  state_id == 2
end

If you actually have a bunch of different attributes that are required when state_id is 3, not just a note, then you may want something like this:

validates :approver_note, :presence => true, :if => :green_state?
validates :po_number, :presence => true, :if => orange_state?

def green_state?
  state_id == 3
end

def orange_state?
  state_id == 2
end

(Replace "green" with -- I dunno -- "high_documentation" or whatever makes sense in your world.)

Or maybe you want to let the state decide what it is:

def green_state?
  state.green?
end

It really does help to make the terminology in your code adhere more closely to your real-world language, as opposed to "3" and "2".

like image 182
Rob Davis Avatar answered Oct 05 '22 06:10

Rob Davis