【问题标题】:Set activerecord model defaults before mass assignment initialize在批量分配初始化之前设置 activerecord 模型默认值
【发布时间】:2014-11-11 12:05:24
【问题描述】:

在将对象从ModelAController#new 传递到视图之前,我需要在ModelA 中设置默认值(来自远程服务)。我为此使用了after_initialize。但是,在#create 我有一个问题。如果我使用model_b.create_model_a(some_attributes),属性在初始化时传入,然后被after_initialize调用覆盖:

class ModelA < ActiveRecord::Base
  after_initialize :set_defaults, if: :new_record?

  def set_defaults
    self.c = "default"
    #actually a remote call, not something can be set as database default
  end
end

class ModelB < ActiveRecord::Base
  belongs_to :model_a
end

class ModelAController < ApplicationController
  #ModelA is nested under ModelB in routes.rb

  #GET /model_bs/:model_b_id/model_as/new
  def new
    model_b = ModelB.find(params[:model_b_id])
    #no problem
    respond_with model_b.build_model_a
  end

  #POST /model_bs/:model_b_id/model_as
  def create
    model_b = ModelB.find(params[:id])
    #problem:
    respond_with model_b.create_model_a({c: "not default"})
    #at this point the model_a instance still has attribute c set to "default"
  end
  ...
end

我可以将创建步骤分开:

model_b = ModelB.find(params[:id])
model_a = model_b.build_model_a #should fire after_initialize
model_a.update_attributes({c: "not default"}) #overwrite default c value

但我觉得这让 ModelA 的生命周期对其他程序员来说有点像陷阱。这看起来像是将最后两行重构为一条的明显候选者,但这会再次产生这个问题。有没有更简洁的解决方案?

【问题讨论】:

    标签: ruby-on-rails activerecord callback mass-assignment


    【解决方案1】:

    进行条件赋值:

    def set_defaults
      self.c ||= "default"
    end
    

    或者在属性阅读器中设置一个默认值,而不是 after_initialize 钩子。这样你只有在你真正需要属性值时才设置默认值,所以如果你不需要它,它会为你节省一个远程调用:

    def c
      super || self.c = 'default'
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-04
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      相关资源
      最近更新 更多