0

updateRailsアクションでアクションをリファクタリングしようとしてusersいます。これにより、送信したリンクをクリックして確認した後にのみ、自分の電子メールアドレスを変更できます。

class UsersController < ApplicationController

  before_filter :authorized_user

  def update
    current_email = @user.email
    new_email = params[:user][:email].downcase.to_s
    if @user.update_attributes(params[:user])    
      if new_email != current_email
        @user.change_email(current_email, new_email)     
        flash[:success] = "Please click on the link that we've sent you."
      else
        flash[:success] = "User updated."
      end
      redirect_to edit_user_path(@user)
    else
      render :edit
    end
  end

  def confirm_email
    @user = User.find_by_email_token!(params[:id])
    @user.email = @user.new_email
    @user.save
  end

  private

  def authorized_user
    @user = User.find(params[:id])
    redirect_to(root_path) unless current_user?(@user)
  end

end

この関数は、新しい電子メールをデータベース フィールドに保存しますnew_email。ユーザーがURL を通じてemail確認した後にのみ置き換えられます。new_email

class User < ActiveRecord::Base

  def change_email(old_email, new_email)
    self.email = old_email
    self.new_email = new_email.downcase    
    self.send_email_confirmation_link  
  end

end

after_saveコードは部分的に機能しますが、おそらくコールバックを使用するか、少なくともより多くのコードをモデルに移動することによって、これを行うためのよりエレガントな方法があるかどうか疑問に思います。

これを行う最良の方法は何ですか?

助けてくれてありがとう!

PSこれを使用することを提案しないでくださいDevise。私は本当にここで独自の認証システムを構築したいと思っています:-)

4

2 に答える 2

0

ビジネス ロジックを実行するために ActiveRecord コールバックを使用しないことをお勧めします。ActiveRecord モデルは、データベースの永続化レイヤーの薄いラッパーにすぎません。

コントローラーのコードを変更する方法を見てください。

def update
  if UpdatesUserCheckingEmail.new(@user, params[:user], flash).execute!
    redirect_to edit_user_path(@user)
  else
    render :edit
  end
end

すべてのビジネス ロジックは、すべてのビジネス ロジックをカプセル化する外部オブジェクトによって実行されます (app/services/updates_user_checking_email.rb に配置できます)。

class UpdatesUserCheckingEmail
  attr_reader :user, :user_params, :flash

  def initialize(user, user_params, options = {})
    @user = user
    @user_params = user_params
    @flash = options[:flash]
  end

  def execute!
    if user.update_attributes(user_params)
      if new_email != current_email
        user.change_email(current_email, new_email)     
        flash[:success] = "Please click on the link that we've sent you."
      else
        flash[:success] = "User updated."
      end
    end
  end

  private

  def current_email
    user.email
  end

  def new_email
    user_params[:email].downcase.to_s
  end

end

また、電子メールを送信するロジックを ActiveRecord モデルの外に移動し、専用のサービス オブジェクト内に移動することをお勧めします。これにより、将来のアプリの変更 (およびテスト) がはるかに簡単になります。

これらの概念の詳細については、http: //blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/を参照してください。

于 2013-06-24T09:41:25.837 に答える
0

データベースの更新前にチェックする必要があるため、データベースの更新後にチェックcurrent_emailしないでください。new_emailもう 1 つは、電子メールをデータベースに更新した後、ユーザーにリンクを送信することです。new_emailそのため、「ユーザーがURL を介して確認した後にのみ電子メールが置き換えられる」という目標を達成できませんでした。ユーザーのメールを更新するための新しいアクションを作成するか、UserController の更新アクションでユーザーが「メールのリセット」のメールを受け取ったときにユーザーのメールを更新するためのロジックを記述する必要があります。以下は、問題を解決するための簡単な方法です。

class UsersController < ApplicationController
  def send_email_rest
    @user.change_email(@user.email, params[:new_email]) if params[:new_email].present?
  end
  def update
    if @user.update_attributes(params[:user])  
      #stuff you want to do
    end
  end
end

それが役立つことを願っています!!!

于 2013-06-24T09:42:08.060 に答える