【问题标题】:Rails make record readonly after update attributeRails 在更新属性后将记录设为只读
【发布时间】:2026-01-01 09:00:01
【问题描述】:

我的模型有一个属性void。如果void 为真,我希望记录是只读的。 我试过了:

def readonly?
  self.void
end

但这会使我无法保存记录,因为在我保存之前 void 已经为真。使用void=true 保存记录会引发ActiveRecord::ReadOnlyRecord 异常。所以我永远无法真正将void=true 存储在数据库中。

我保存void=true后如何记录readonly

【问题讨论】:

  • 你能提供你的验证吗?
  • @OlegSobchuk 我只验证其他字段而不是无效,所以我认为这无关紧要吗? (或者我错了吗?)。在设置void=true 后保存记录会导致它引发ActiveRecord::ReadOnlyRecord 错误,这似乎与rails 验证无关。

标签: ruby-on-rails-4 rails-activerecord


【解决方案1】:
def readonly?
  persisted? && void
end

编辑

它只适用于新记录。

如果您需要使用持久化记录,您可以通过以下方式进行:

在您的模型中:

attr_accessor :editable

def readonly?
  editable || !void ? false : true
end

【讨论】:

  • 似乎不起作用,我认为这只有在对象是 new_record 时才起作用?。
  • 已编辑,查看。如果你觉得我的回答有用,请标记它有用,谢谢
  • 我应该对editable 做点什么吗?我认为它是nil
  • 没错,但现在在控制器中,您可以根据需要设置true。例如:params[:name_your_object].merge(edidable: true) if current_user.admin?
【解决方案2】:

您可以尝试检查void 属性是否发生了变化?

例如

def readonly?
  !void_just_changed? && void
end

def void_just_changed?
  void_was.blank? && void?
end

您可以将void_just_changed? 修改为适合您的任何内容,例如允许将 void 设置回 false。

【讨论】:

  • 所以我需要添加另一个字段来跟踪更改?希望有一种更清洁的方法:(
  • 不,这不是另一个字段。 void_was 是 Rails 生成的方法,它在更改之前返回 void 的值。见api.rubyonrails.org/classes/ActiveModel/Dirty.html
【解决方案3】:

我找到了一种不添加任何变量的方法,但是,结果行为有点不同。

def readonly?
  begin
    prev = self.class.find(self.id)
    prev.void && self.void
  rescue ActiveRecord::RecordNotFound
    false
  end
end

使用此方法,记录将正确标记为只读,但允许修改其属性,您将无法保存它。相反,如果您从 readonly? 方法手动返回 true,则将引发 ReadOnlyRecord (我认为这是更可取的)。 如果有人能解释原因,那就太好了。

【讨论】:

    【解决方案4】:

    我还有另一个变种:

      def readonly?
        !persisted? || void_changed? ? false : void
      end
    

    意思是每次更改void记录时不是只读的,其他情况下是只读的?取决于 void

    【讨论】: