【问题标题】:ActiveRecord not updating dirty attribute on save / update. Create OK. Possible Inheritance issueActiveRecord 在保存/更新时不更新脏属性。创建确定。可能的继承问题
【发布时间】:2017-05-14 08:35:15
【问题描述】:

我有一个使用单表继承的类结构如下:

CashAccount > AssetAccount > FinancialAccount

相关控制器代码:

def create
  @financial_account = FinancialAccount.new(financial_account_params)
  respond_to do |format|
    if @financial_account.save
      format.html { redirect_to @financial_account, notice: 'Account was successfully created.' }
    else
      format.html { render :new }
    end
  end
end

def update
  respond_to do |format|
    if @financial_account.update(financial_account_params)
      format.html { redirect_to @financial_account, notice: 'Account was successfully updated.' }
    else
      format.html { render :edit }
    end
  end
end

  def set_financial_account
    @financial_account = FinancialAccount.find_by_id(params[:id])
    unless @financial_account 
      redirect_to root_path, :flash => { :alert => "That Account does not exist." }
      return
    end       
  end

def update_params
  params.require(@financial_account.model_name.param_key)
        .permit(:name, :type, :description)
end

def create_params
  params.require(:financial_account)
        .permit(:name, :type, :description)
end

创作作品。更新没有。没有错误。保存返回 true 但值永远不会改变。以下是在对象更新时调试状态的一些 put:

puts @financial_account.changed? //false
@financial_account.assign_attributes(financial_account_params)
puts @financial_account.changed? //true
@financial_account.description_will_change!
puts @financial_account.changed? //true
puts @financial_account.description //New Value 1
puts @financial_account.save //true
puts @financial_account.description //Old Value
puts @financial_account.update(:description => "New Value 2") //true
puts @financial_account.description //Old Value
@financial_account.description = "New Value 3"
puts @financial_account.description //New Value 3
puts @financial_account.save //true
puts @financial_account.description //Old Value

Description 是 FinancialAccount 类的简单文本属性:

  create_table "financial_accounts", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
    ...
    t.text     "description"
    ...
  end

部分 to_yaml 打印出@financial_account 以查看用户的储值:

delegate_hash:
  name: !ruby/object:ActiveRecord::Attribute::FromUser
    name: name
    value_before_type_cast: Test Account
    type: *1
    value: Test Account
  description: !ruby/object:ActiveRecord::Attribute::FromUser
    name: description
    value_before_type_cast: New Value 1
    type: *1
    value: New Value 1

数据库是PostgreSQL

更新 - DjezzzL 请求的输出

注意:这是一个多租户应用程序,所以我需要设置业务 ID

2.2.4 :001 > Business.current_id = 1
 => 1 
2.2.4 :002 > tmp = FinancialAccount.first
  FinancialAccount Load (0.6ms)  SELECT  "financial_accounts".* FROM "financial_accounts" WHERE "financial_accounts"."business_id" = $1  ORDER BY "financial_accounts"."id" ASC LIMIT 1  [["business_id", 1]]
 => #<RetainedEarningsAccount id: "0a282a84-2561-4820-8f21-b8063c1c2604", type: "RetainedEarningsAccount", name: "Owner's Retained Earnings", created_at: "2017-05-02 05:20:22", updated_at: "2017-05-02 05:20:22", description: "Old Value", business_id: 1, update_balance_flag: false, reference_number: "11", balance_cents: 0> 
2.2.4 :003 > tmp.description = 'new value'
 => "new value" 
2.2.4 :004 > p tmp.save
   (0.2ms)  BEGIN
  FinancialAccount Exists (1.0ms)  SELECT  1 AS one FROM "financial_accounts" WHERE ("financial_accounts"."reference_number" = '11' AND "financial_accounts"."id" != '0a282a84-2561-4820-8f21-b8063c1c2604' AND "financial_accounts"."business_id" = 1) LIMIT 1
  RetainedEarningsAccount Load (0.3ms)  SELECT  "financial_accounts".* FROM "financial_accounts" WHERE "financial_accounts"."type" IN ('RetainedEarningsAccount') AND "financial_accounts"."id" = $1 LIMIT 1  [["id", "0a282a84-2561-4820-8f21-b8063c1c2604"]]
   (0.2ms)  COMMIT
true
 => true 
2.2.4 :005 > p tmp.description
"Old Value"
 => "Old Value" 
2.2.4 :006 > p tmp.reload.description
  RetainedEarningsAccount Load (2.1ms)  SELECT  "financial_accounts".* FROM "financial_accounts" WHERE "financial_accounts"."type" IN ('RetainedEarningsAccount') AND "financial_accounts"."id" = $1 LIMIT 1  [["id", "0a282a84-2561-4820-8f21-b8063c1c2604"]]
"Old Value"
 => "Old Value"

注意:我的属性被标记为脏,所以不是重复的 ActiveRecord not saving after updating attribute

【问题讨论】:

  • 所以你在模型中使用 before 回调?或者您的模型中包含任何日志记录或监控 gem?
  • @spickermann 没有保存或更新任何这些模型的回调。我不使用日志记录或监控 gem。
  • @scottysmalls 首先,我在您的更新操作中没有看到@financial_account 的任何设置器。你有任何 before_action 回调吗?我讲def update; @financial_account = FinancialAccount.find(params[:id]); &lt;try to save and others stuff to do&gt;; end返回更新记录值。您能否提供以下执行以及相应的结果和 SQL 查询:tmp = FinancialAccount.first; tmp.description = 'new value'; p tmp.save; p tmp.description; p tmp.reload.description;
  • @DjezzzL 由于在引用financial_account 时调试没有失败,我认为可以假设但有问题的路径确实通过了 set_financial_account 方法,所以你是对的 - 我应该包括它:见上文。感谢您的彻底。我也为您在上面的查询添加了输出。
  • @scottysmalls 这是来自 tmp.save 的非常有趣的 sql 查询输出。特殊选择 id != 'id'。似乎您有一些特殊的验证。那么您能否分享您的模型定义。

标签: ruby-on-rails ruby activerecord single-table-inheritance


【解决方案1】:
def create
  @financial_account = FinancialAccount.new(create_params)
  respond_to do |format|
    if @financial_account.save
      format.html { redirect_to @financial_account, notice: 'Account was successfully created.' }
    else
      format.html { render :new }
    end
  end
end

def update
  respond_to do |format|
    if @financial_account.update(update_params)
      format.html { redirect_to @financial_account, notice: 'Account was successfully updated.' }
    else
      format.html { render :edit }
    end
  end
end

private

def create_params
  params.require(@financial_account.model_name.param_key)
        .permit(:name, :type, :description)
end

def update_params
  params.require(:financial_account)
        .permit(:name, :type, :description)
end

使用ActiveModel::Naming#param_key 获取多态模型的参数键。同样在这种情况下,最好使用两种单独的方法进行白名单,因为它可以减少代码路径的数量。

【讨论】:

  • 与以前的结果相同。谢谢你的 param_key - 我不知道它,从现在开始会使用它。我同意两种不同的方法在这里要好得多。我更新了我的帖子(我认为应该交换方法名称。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多