I'm working on a Rails app that existing users can invite additional members to join. The problem with this is that the User model exists in different states and in those different states, different sets of information is required.
For example, John is a member of the site and invites Mary. John enters Mary's name and email address, a user record is created in the database for Mary, and an invitation email is sent. After she joins, however, the required set of data changes and we require her to enter additional information (e.g. a password).
I'm still learning Ruby on Rails and I don't see any way to handle this using the standard validation techniques of validates_presence_of
, validates_format_of
, etc. Can anyone point me in the right direction
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.
So remember folks, validates is for Rails validators (and custom validator classes ending with Validator if that's what you're into), and validate is for your custom validator methods.
Rails validation defines valid states for each of your Active Record model classes. They are used to ensure that only valid details are entered into your database. Rails make it easy to add validations to your model classes and allows you to create your own validation methods as well.
The easiest is to use :if
as follows:
class User < ActiveRecord::Base
validate_presence_of :name
validate_presence_of :age, :if => Proc.new { |user| user.signup_step >= 2 }
# ... etc
end
or:
class User < ActiveRecord::Base
validate_presence_of :name
validate_presence_of :age, :if => :registering?
def registering?
signup_step >= 2
end
end
You can also use the validate
method to define any complex, custom logic. For example:
class User < ActiveRecord::Base
validate :has_name_and_email_after_invitation
validate :has_complete_profile_after_registration
def has_name_and_email_after_invitation
if ... # determine if we're creating an invitation
# step 1 validation logic here
end
end
def has_complete_profile_after_registration
if ... # determine if we're registering a new user
# step 2 validation logic here
end
end
end
(In the above example, you could actually define the validation rules in has_name_and_email_after_invitation
with regular validates_xxx_of
calls, because they must apply in step 2 as well, but using two methods for the separate steps gives you maximum flexibility.)
And, for DRYin'up your code a bit, you can use with_options
, like this:
class Example < ActiveRecord::Base
[...]
def registering?
signup_step >= 2
end
with_options(:if => :registering?) do |c|
c.validates_presence_of :name
end
with_options(:unless => :registering?) do |c|
c.validates_presence_of :contact_details
end
[...]
end
Find out more about with_options
here:
http://apidock.com/rails/v2.3.2/Object/with_options
There's even a screencast by RailsCasts:
http://railscasts.com/episodes/42-with-options
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With