如何以独立于实现的方式从存储库返回结果和错误?

时间:2014-05-31 05:58:17

标签: ruby-on-rails ruby-on-rails-4 design-patterns repository

我试图使用Rails实现Repository模式的一个子集,并且在理解如何从类或存储库传递错误,返回控制器然后进入视图时遇到一些麻烦。

例如,我有一个类DomainClass,它只允许用户注册一个子域。那里有一些规则 - 它必须是唯一的,必须只包含字母和数字 - 你有什么。

当一个或多个模型验证失败时,我想以某种方式将此值传递给视图。在传递这些错误的同时,我还必须返回" false"对控制器来说,它知道无论我试图做什么都失败了。

这看起来很简单。我在这里缺少什么?

Class - if this fails, I should pass the validation error to my controller.    

  # Create a domain ID and return the newly injected ID.do
  # If a new Domain ID couldn't be created for any reason,
  # return FALSE.
  def create_domain(domain_name)
    @domain.domain_name = domain_name
    if @domain.save
      return @domain.id
    else
      return false
    end
  end

Controller - From here, I should return the model's validation error to the view.

  # Try to save our user to the database
  if new_user = @domain.create_domain(domain_name)
    # Do things that are good.
  else
    # Return model's validation error here.
  end

1 个答案:

答案 0 :(得分:1)

我看到了两种设计create_domain的选项,当你在一些非ActiveRecord商店上重新实现它时仍然有意义。您将使用哪一个取决于您期望使用它的情况。

  1. 定义一个类来保存所有create_domain可能的返回值。这将是一个开始:

    class SaveResult < Struct.new :id, :errors
      def succeeded?
        errors.empty?
      end
    end
    

    create_domain

    return SaveResult.new *(
      if @domain.save
        @domain.id, []
      else
        nil, @domain.errors # this is an ActiveModel::Errors, but tell your callers it's a Hash
      end
    )
    

    然后调用者可以执行类似

    的操作
    result = @domain.create_domain name
    if result.succeeded?
      # celebrate
    else
      # propagate errors to model
    end
    

    这种设计的缺点是呼叫者必须记住检查是否有错误。如果大多数调用者必须明确地处理错误(如上所述),那么它将很有效。

  2. 定义出现错误时引发的异常:

    class SaveError < Exception
      attr_accessor :errors # again, pretend it's just a hash
    
      def initialize(errors)
        self.errors = errors
      end
    
    end
    

    create_domain

    if @domain.save
      return @domain.id
    else
      raise SaveResult, @domain.errors
    emd
    

    然后调用者可以执行类似

    的操作
    begin
      new_user_id = @domain.create_domain name
      # celebrate
    rescue SaveError => e
      # propagate errors to model
    end
    

    这种设计的缺点是异常处理比if / else更难写。它的优点是,如果你只是允许所有这些异常传播出调用者并在ActionController#rescue_from或类似的地方处理它们,那么调用者根本不需要编写任何错误处理。 / p>