Hi, I have a user model with an e-mail field. When a user registers for the site, I want them to confirm their email address by typing it in again. If they change their email address, I want them to confirm their email address by typing it in again. However, the user might change things on their account not related to their email address, such as their phone number, and they should not have to confirm their email address. I suppose I can add an email_confirmation field to the database, and then use validates_confirmation_of :email But, this seems rather wasteful and silly to store both the email and the email_confirmation. I understand that the model need not store the field in the database, but then in that case User.find(:first) ... fiddle with attributes other than email address ... User.save (rightly) throws an error because the email_confirmation field doesn''t match email. What is the proper way to model a phony email_confirmation field, such that confirmation validation is only fired when the e-mail address is actually updated? Thank you. Regards, Rich -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060816/3853d173/attachment.html
You don''t need to make a database field for the email_confirmation, you can use it simply by including: validates_confirmation_of :email Rails handles the creation of a virtual attribute for you.
> What is the proper way to model a phony email_confirmation > field, such that confirmation validation is only fired when the > e-mail address is actually updated?Sorry hit reply before including the rest of my reply validates_confirmation_of :email :if => :change_email? def change_email? # make sure that the user requested an email change end
> > You don''t need to make a database field for the email_confirmation, > you can use it simply by including: > > validates_confirmation_of :email >Yes, that''s where I started. However, when I need to update something completely unrelated, the email confirmation rule gets in the way: user = User.find(1) user.update_attributes(:contact_by_phone => true) => false user.errors.each_full { |msg| puts msg } => ''Email confirmation can''t be blank'' So, how can I structure the email confirmation rule to only fire when the email address is changing, either through the creation of a new user, or a request to actually update the email address? Thank you. Regards, Rich
In theory (i.e. untested). You could store the existing email address in an after_initialize handler. Then, in a before_save (or maybe before_validate?) handler, you could check if the email was different. If so, you could manually add errors to the object to prevent it from being saved. Does that make sense? Chris On 8/16/06, Duzenbury, Rich <rduzenbury@biltd.com> wrote:> > > > You don''t need to make a database field for the email_confirmation, > > you can use it simply by including: > > > > validates_confirmation_of :email > > > > Yes, that''s where I started. However, when I need to update something > completely unrelated, the email confirmation rule gets in the way: > > user = User.find(1) > user.update_attributes(:contact_by_phone => true) => false > user.errors.each_full { |msg| puts msg } => ''Email confirmation can''t be > blank'' > > > So, how can I structure the email confirmation rule to only fire when > the email address is changing, either through the creation of a new > user, or a request to actually update the email address? > > Thank you. > > Regards, > Rich > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
> > validates_confirmation_of :email > :if => :change_email? > > def change_email? > # make sure that the user requested an email change > endHi Jim, This is getting to the crux of the issue. I am looking for the right way to implement just such a ''change_email?'' function. In my view, I want to display the current e-mail address, and allow the user to type over it if they choose. So, I currently use <% form_for :user, @user do |f| -%> <table> <tr> <td><label for="email">Email *</label></td> <td><%= f.text_field :email %></td> </tr> <tr> <td><label for="email_confirmation">Confirm Email *</label></td> <td><%= f.text_field :email_confirmation %></td> </tr> (and so on) When the record is retrieved from the db, of course the email field is filled. The confirmation is not: user = User.find(1) user.email "foo@example.com" user.email_confirmation nil And therefore .save will not complete because user.email and user.email_confirmation don''t match. This makes perfect sense, as there is no database field for email_confirmation. So, perhaps I ought to initialize user.email_confirmation = user.email when a record is created or retrieved? I''m not sure how...but then the validation should always work, even if nothing gets changed. Or, somehow, I would need to compare the email stored in the db to a different email field that comes back from the form. Perhaps I should add an email_new accessor to the model, and then the view points to it? I would still need to initialize email_new with the current value of email, I guess. Anyway, this is why I wrote the list to begin with. Not sure how to deal with the ''phony'' confirmation fields. Thank you. Regards, Rich
> > > > > validates_confirmation_of :email > > :if => :change_email? > > > > def change_email? > > # make sure that the user requested an email change > > end > > Hi Jim, > > This is getting to the crux of the issue. I am looking for the right > way to implement just such a ''change_email?'' function. > > In my view, I want to display the current e-mail address, and allowthe> user to type over it if they choose. So, I currently use > <% form_for :user, @user do |f| -%> > <table> > <tr> > <td><label for="email">Email *</label></td> > <td><%= f.text_field :email %></td> > </tr> > <tr> > <td><label for="email_confirmation">Confirm Email *</label></td> > <td><%= f.text_field :email_confirmation %></td> > </tr> > > (and so on) > > When the record is retrieved from the db, of course the email field is > filled. The confirmation is not: > user = User.find(1) > user.email > "foo@example.com" > user.email_confirmation > nil > > And therefore .save will not complete because user.email and > user.email_confirmation don''t match. > > This makes perfect sense, as there is no database field for > email_confirmation. So, perhaps I ought to initialize > user.email_confirmation = user.email when a record is created or > retrieved? I''m not sure how...but then the validation should always > work, even if nothing gets changed. > > Or, somehow, I would need to compare the email stored in the db to a > different email field that comes back from the form. Perhaps I should > add an email_new accessor to the model, and then the view points toit?> I would still need to initialize email_new with the current value of > email, I guess. > > Anyway, this is why I wrote the list to begin with. Not sure how to > deal with the ''phony'' confirmation fields. > > Thank you. > > Regards, > Rich >Well, for the archives, I did the following: class User < ActiveRecord::Base validates_confirmation_of :email def after_find self.email_confirmation = self.email end end This way, any new or changing email addresses cause the validates_confirmation_of to fire, and, in cases where other things are getting updated, such as user = User.find(1) user.update_attributes(:contact_by_phone => false) user.save The validation will operate successfully. Thanks. Regards, Rich