<?xml version="1.0" encoding="UTF-8"?>
<wiki>
  <body>&lt;p&gt;Add the ability for users to change their email address to something other that what they registered with. Users must be logged in to perform this operation and they need to verfiy the action via email before the change takes place.&lt;br /&gt;
Migration&lt;/p&gt;
&lt;p&gt;script/generate migration New Email Address&lt;/p&gt;
&lt;p&gt;class NewEmailAddress &amp;lt; ActiveRecord::Migration&lt;br /&gt;
  def self.up&lt;br /&gt;
     add_column :users,  :new_email, :string&lt;br /&gt;
     add_column :users, :email_activation_code, :string, :limit =&amp;gt; 40&lt;/p&gt;
end
def self.down
remove_column :users, :email_activation_code
remove_column :users, :new_email
end
&lt;p&gt;end&lt;/p&gt;
&lt;p&gt;Model&lt;/p&gt;
&lt;p&gt;user.rb&lt;/p&gt;
def change_email_address(new_email_address)
@change_email  = true
self.new_email = new_email_address
self.make_email_activation_code
end
def activate_new_email
@activated_email = true
update_attributes(:email=&amp;gt; self.new_email, :new_email =&amp;gt; nil, :email_activation_code =&amp;gt; nil)
end
def recently_changed_email?
@change_email
end
protected
def make_email_activation_code
self.email_activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
end
&lt;p&gt;user_observer.rb&lt;/p&gt;
def after_save(user)
&lt;p&gt;user.recently_activated?    &lt;br /&gt;
    UserNotifier.deliver_change_email(user) if user.recently_changed_email?  &lt;br /&gt;
  &amp;#8230;&lt;br /&gt;
  &amp;#8230;&lt;br /&gt;
  end&lt;/p&gt;
&lt;p&gt;user_notifier.rb&lt;/p&gt;
def change_email(user)
setup_email(user)
@recipients  = &amp;#8220;#{user.new_email}&amp;#8221;
@subject    += &amp;#8216;Request to change your email&amp;#8217;
@body[:url]  = &amp;#8220;http://#{SITE_URL}/account/activate_new_email/#{user.email_activation_code}&amp;#8221;
end
&lt;p&gt;Controller&lt;/p&gt;
&lt;p&gt;account_controller.rb&lt;/p&gt;
def change_email
return unless request.post?
unless params[:email].blank?
self.current_user.change_email_address(params[:email])
self.current_user.save
@changed = true
else
flash[:notice] = &amp;#8220;Please enter an email address&amp;#8221;
end
end
def activate_new_email
flash.clear
return unless params[:id].nil? or params[:email_activation_code].nil?
activator = params[:id] || params[:email_activation_code]
@user = User.find_by_email_activation_code(activator)
if @user and @user.activate_new_email
redirect_back_or_default(:controller =&amp;gt; &amp;#8216;/account&amp;#8217;, :action =&amp;gt; &amp;#8216;index&amp;#8217;)
flash[:notice] = &amp;#8220;The email address for your account has been updated.&amp;#8221;
else
flash[:notice] = &amp;#8220;Unable to update the email address.&amp;#8221;
end
end
&lt;p&gt;Views&lt;/p&gt;
&lt;p&gt;account/change_email.rhtml&lt;/p&gt;
&lt;p&gt;&amp;lt;% unless @changed &lt;span&gt;&amp;gt;&lt;br /&gt;
&lt;h1&gt;Change account email address &amp;#8211; Step 1 of 3&lt;/h1&gt; &lt;br /&gt;
&lt;p&gt;Enter the new email address that you wish to use for this account&lt;/p&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&lt;/span&gt;= start_form_tag &lt;span&gt;&amp;gt;&lt;br /&gt;
&lt;p&gt;&lt;label for=&quot;email&quot;&gt;Email Address&lt;/label&gt; &lt;br /&gt;
&amp;lt;&lt;/span&gt;= text_field_tag &amp;#8216;email&amp;#8217; &lt;span&gt;&amp;gt;&amp;lt;&lt;/span&gt;= submit_tag &amp;#8216;Update my email&amp;#8217; %&amp;gt;&lt;/p&gt;&lt;/p&gt;
&lt;/form&gt;
&lt;p&gt;&amp;lt;% else %&amp;gt;&lt;br /&gt;
&lt;h1&gt;Change account email address &amp;#8211; Step 2 of 3&lt;/h1&gt;&lt;/p&gt;
&lt;p&gt;
Thanks. An email has been sent to the address provided (&amp;lt;%= self.current_user.new_email %&amp;gt;).
&lt;/p&gt;
&lt;p&gt;
Please follow the instructions contained within the email
to complete this process.
&lt;/p&gt;
&lt;p&gt;&amp;lt;% end %&amp;gt;&lt;/p&gt;
&lt;p&gt;user_notifier/change_email.rhtml&lt;/p&gt;
&lt;p&gt;Please visit this url to update your account to use the new email address:&lt;/p&gt;
&amp;lt;%= @url %&amp;gt;
&lt;p&gt;account/activate_new_email.rhtml&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;empty&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Suggestion from Barry Hess:&lt;/p&gt;
&lt;p&gt;I wanted this new email address field to undergo the same validation as the email address entered when the user signs up for my site. To make this happen, I added some new validation steps and slightly modified controller action.&lt;br /&gt;
Model&lt;/p&gt;
&lt;p&gt;I have the following email validations in user.rb:&lt;/p&gt;
validates_presence_of     :email
validates_length_of       :email,
:within =&amp;gt; 6..100
validates_uniqueness_of   :email,
:case_sensitive =&amp;gt; false
validates_format_of       :email,
:with =&amp;gt; /^([^&lt;code&gt;\s]+)&lt;/code&gt;((?:[-a-z0-9]&lt;ins&gt;\.)&lt;/ins&gt;[a-z]{2,})$/
&lt;p&gt;For the new email address, I don&#8217;t want any validation to occur unless I&#8217;m specifying a new email address through my &#8220;update email&#8221; screens. Generally speaking, if there is no value given for user.new_email, then I don&#8217;t wish to validate. However, if user.new_email has something in it, validation needs to occur. The following code makes this happen:&lt;/p&gt;
validates_length_of       :new_email,
:within =&amp;gt; 6..100,
:if =&amp;gt; :new_email_entered?
validates_format_of       :new_email,
:with =&amp;gt; /^([^&lt;code&gt;\s]+)&lt;/code&gt;((?:[-a-z0-9]&lt;ins&gt;\.)&lt;/ins&gt;[a-z]{2,})$/,
:if =&amp;gt; :new_email_entered?
&lt;ol&gt;
	&lt;li&gt;Assures that updated email addresses do not conflict with&lt;/li&gt;
	&lt;li&gt;existing email addresses. &lt;br /&gt;
  def validate&lt;br /&gt;
    if User.find_by_email(new_email)&lt;br /&gt;
      errors.add(new_email, &amp;#8220;is already being used&amp;#8221;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;/li&gt;
&lt;/ol&gt;
protected
def new_email_entered?
!self.new_email.blank?
end
&lt;p&gt;(I&#8217;m sure that validates_format_of code can be DRY&#8217;d up.)&lt;br /&gt;
Controller&lt;/p&gt;
&lt;p&gt;I also updated the account_controller.rb&#8217;s change_email action a bit. Since I&#8217;m now serving up validation messages, I want to avoid modifying @changed unless validation was successful. The check for a blank parameter is still appropriate as there is no inherent validation in the model to check for this.&lt;/p&gt;
&lt;p&gt;I will also be using the form_for helper in the view to relate the form with the user model.&lt;/p&gt;
def change_email
@user = self.current_user
return unless request.post?
unless params[:user][:email].blank?
@user.change_email_address(params[:user][:email])
if @user.save
@changed = true
end
else
flash[:notice] = &amp;#8220;Please enter an email address&amp;#8221;
end
end
&lt;p&gt;View&lt;/p&gt;
&lt;p&gt;account/change_email.rhtml&lt;/p&gt;
&lt;p&gt;&amp;lt;%= error_messages_for :user %&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;% unless @changed -%&amp;gt;&lt;br /&gt;
  &lt;h1&gt;&lt;br /&gt;
    Step 1 of 3&lt;/p&gt;
&lt;/h1&gt;
&amp;lt;% form_for :user do |f| -%&amp;gt;
&lt;p&gt;
      &lt;label for=&quot;user_email&quot;&gt;Email&lt;/label&gt;
&amp;lt;%= f.text_field :email %&amp;gt;
&amp;lt;%= submit_tag &amp;#8220;Update email!&amp;#8221; %&amp;gt;
&amp;lt;% end -%&amp;gt;
&lt;p&gt;&amp;lt;% else -%&amp;gt;&lt;br /&gt;
  &lt;h1&gt;&lt;br /&gt;
    Step 2 of 3&lt;/p&gt;
&lt;/h1&gt;
&lt;p&gt;
Thanks. An email has been sent to the address provided
(&amp;lt;%= self.current_user.new_email %&amp;gt;).
&lt;/p&gt;
&lt;p&gt;
Please follow the instructions contained within the
email to complete this process.
&lt;/p&gt;
&lt;p&gt;&amp;lt;% end -%&amp;gt;&lt;/p&gt;</body>
  <created-at type="datetime">2008-10-24T03:47:54-07:00</created-at>
  <id type="integer">71694</id>
  <permalink>change-email-address</permalink>
  <repository-id type="integer">67186</repository-id>
  <title>Change Email Address</title>
  <updated-at type="datetime">2008-10-24T03:47:54-07:00</updated-at>
  <user-id type="integer">30799</user-id>
</wiki>
