干燥此 Ruby 代码

DRYing this Ruby code

最近,我开始使用 Rubocop,并一直在努力思考我的代码是否可以写得更好。我有一个非常相似的创建和更新方法。 Rubocop 抱怨该方法的代码行太多 [12/10]。我想知道您将如何在这里遵循 DRY 原则。在我看来, respond_to 应该被带到它自己的私有方法中。但我不知道什么是最好的方法,因为:

  1. 闪光可以是:成功或:危险
  2. 一个检查模型是否保存,另一个检查模型是否更新。
  3. 不同的渲染取决于模型是否保存或是否有错误

我也不知道我是否应该让它一个人呆着。不过,它是如此多余的事实确实让我着迷。最终我想要最干净的代码,我只是不确定我是否应该 DRY 这个方法

  def create
    @category = Category.new(category_params)

    respond_to do |format|
      if @category.save
        flash[:success] = 'Category Successfully Created'
        format.html { redirect_to admin_category_path(@category) }
        format.json { render :show, status: :created, location: @category }
      else
        flash[:danger] = 'Errors in creating category, see below'
        format.html { render :new }
        format.json { render json: @category.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    @category = Category.find(params[:id])

    respond_to do |format|
      if @category.update(category_params)
        flash[:success] = 'Category Successfully updated!'
        format.html { redirect_to admin_category_path(@category) }
        format.json { render :show, status: :created, location: @category }
      else
        flash[:danger] = 'Errors in updating category, missing information'
        format.html { redirect_to action: 'edit', id: @category.id }
        format.json { render json: @category.errors, status: :unprocessable_entity }
      end
    end
  end

尝试从 createupdate 中创建一个方法没有任何意义,因为它们有两个截然不同的目的。

相反,您可以考虑以下事项:

  • 你真的需要 json 格式吗?如果你不使用它,你可以安全地删除那些行;
  • update 中删除 @category = Category.find(params[:id]) 并将其移动到 before_action

    中的方法
    before_action :find_category, only: [:edit, :update]
    
    def find_category
      @category = Category.find(params[:id])
    end
    
  • 最后但同样重要的是,Rubocop 并不总是有正确的答案:专注于清晰!

除了消息中的单个单词外,所有成功处理都是相同的; JSON 对错误的处理是相同的。因此,这些部分可以提取到由 create 和 update 调用的方法中。不仅代码会更简洁,而且 reader 哪些行为相同,哪些行为不同也会一目了然。我没有 运行 或测试过这段代码,但它是:

def handle_success(created_or_updated)
  verb = created_or_updated == :created ? 'Created' : 'Updated'
  flash[:success] = "Category Successfully #{verb}"
  format.html { redirect_to admin_category_path(@category) }
  format.json { render :show, status: :created, location: @category }
end


def handle_failure_json
  format.json { render json: @category.errors, status: :unprocessable_entity }
end


def create
  @category = Category.new(category_params)

  respond_to do |format|
    if @category.save
      handle_success(:created)
    else
      flash[:danger] = 'Errors in creating category, see below'
      format.html { render :new }
      handle_failure_json
    end
  end
end


def update
  @category = Category.find(params[:id])

  respond_to do |format|
    if @category.update(category_params)
      handle_success(:updated)
    else
      flash[:danger] = 'Errors in updating category, missing information'
      format.html { redirect_to action: 'edit', id: @category.id }
      handle_failure_json
    end
  end
end

看看这里,这是最佳做法

http://edgeapi.rubyonrails.org/classes/ActionController/Responder.html