创建或更新Rails 4 - 更新但也创建(重构)

时间:2015-01-13 16:50:55

标签: ruby-on-rails postgresql

在我的Rails API中,我的Child模型中包含以下代码:

before_create :delete_error_from_values, :check_errors, :update_child_if_exists

def delete_error_from_values
    @new_error = self.values["error"]
    @values = self.values.tap { |hs| hs.delete("error") }
end

def update_child_if_exists
    conditions = {type: self.type, parent_id: self.parent_id}

    if existing_child = Child.find_by(conditions)
        new_values = existing_child.values.reverse_merge!(@values)
        hash = {:values => new_values}
        existing_child.update_attributes(hash)
    end
end

def check_errors
    if self.type == "error"
        conditions = {type: self.type, parent_id: self.parent_id}
        if existing_child = Child.find_by(conditions) 
            bd_errors = existing_child.error_summary
            bd_errors[@new_error] = bd_errors[@new_error].to_i + 1
            hash = {:error_summary => bd_errors}
            existing_child.update_attributes(hash)
        else
            self.error_summary = {@new_error => 1}
        end
    end
end

除了一个小细节之外,它的工作方式与预期相同:如果类型和parent_id的记录已经存在,则会更新子级,但也会创建它。我怎样才能重构这个以阻止创作呢?

我已尝试加入return false,但如果我这样做,则更新失败。

我希望有find_or_create_by之类的内容,但我不确定如何在这种情况下使用它。

1 个答案:

答案 0 :(得分:1)

您可以按照以下方法重构代码:

def create 
  @parent = Parent.find(params[:parent_id]) 
  existing_child = Child.where(type: child_params[:type], parent_id:    
  child_params[:parent_id]).first 

  if existing_child.present? 
    existing_child.update_attributes(attribute: value_1) 
  else 
    @child = @parent.child.build(child_params) 
  end 
  #other saving related code goes here.
end

这只是一个基本的例子。 尝试创建单独的实例方法以保持Contrller DRY。 :)