0

私には、とりわけユーザーのアドレスを格納するユーザーモデルがあります。アカウント(user_sessionsコントローラー)を作成するとき、名前の存在を検証したいだけです。アドレスはオプションです。

アカウントをアップグレードするとき(コントローラーのアップグレード)、完全なアドレスが入力されていることを確認したいと思います。

コントローラーに基づいて条件付き検証を行うための洗練された方法はありますか?

4

2 に答える 2

3

古いモデルを継承した新しいモデルを作成してみましたか。だからあなたは持つことができます:

class User < ActiveRecord::Base
  attr_accessible :name, :address
  validates_presence_of :name
end

class UpgradedUser < User
  validates_precense_of :address
end

Userクラスから継承するため、UpgradedUserクラスにはアドレスと名前の両方の検証があります。そして、このソリューションはまだ1つのデータベーステーブルのみを使用します。これらはまだ1つのテーブルであるため:account_status、アカウントがアップグレードされているかどうかを判断するには、列などを追加する必要があります。

upgrade_usersコントローラーには、標準の更新方法があります。

class upgraded_users_controller   

  def update
    @upgraded_user = UpgradedUser.find params[:id]
    respond_to do |format|
      if @upgraded_user.update_attributes params[:user]
        format.html { redirect_to @upgraded_user }
      end
    end

このメソッドは、同じUserテーブルにアクセスしますが、代わりにモデルusers_controller を介してアクセスするだけなのでUpgradedUser、名前とアドレスの両方の存在について保存時にバリデーターをチェックします。

于 2012-11-24T23:10:02.557 に答える
2

デコレータ/インスタンス拡張

これを実現するには、デコレータパターンを使用できます。インスタンス拡張は別のオプションです。私たちはrubyを使用していて、インスタンス拡張の方法がもっと楽しいので、次のようにします。

class User < ActiveRecord::Base
  validate :decorator_validations

  protected

  def decorator_validations
    # noop at this point
  end
end


module User::Upgrader

  def upgrade!
    # do whatever upgrade operation is needed
    save
  end

  protected

  def decorator_validations
    super
    self.errors.add(:address, 'needs to be provided') unless self.address.present?
  end
end

そしてあなたのコントローラーで:

def upgrade
  @user = User.find(params[:id])
  @user.extend User::Upgrader
  if @user.upgrade!
    # success case
  else
    # failure case
  end
end

コマンドパターン

別の方法は、コマンドパターンを使用することです。

class UserUpgrader

 def initialize(user)
   @user = user
 end

 def call
   validate_upgrade_state
   return false if @user.errors.present?
   @user.update_attribute(:upgraded, true)
 end

 protected

 def validate_upgrade_state
   @user.errors.add(:address, 'must be present') unless @user.address.present?
 end
end

この場合、コントローラーは次のようになります。

@user = User.find(params[:id])
if UserUpgrader.new(@user).call
 # success case
else
 # failure case
end

これらのソリューションの両方の良いところは、非常にテスト可能であるということです。

于 2012-11-25T02:17:57.530 に答える