如何在 Rails 中将数据库字段设置为只读?

发布于 2024-08-07 03:11:21 字数 63 浏览 5 评论 0原文

我有一个包含某个字段的数据库表,一旦将其插入数据库,就不可能更新该字段。如何告诉我的模型它不应允许更新某个字段?

I have a database table with a certain field which should be impossible to update once it has been inserted to the database. How do I tell my model that it shouldn't allow updating of a certain field?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抱猫软卧 2024-08-14 03:11:21

您想使用 attr_readonly< /a>:

列为只读的属性将用于创建新记录,但更新操作将忽略这些字段。

class Customer < ActiveRecord::Base
    attr_readonly :your_field_name
end

You want to use attr_readonly:

Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.

class Customer < ActiveRecord::Base
    attr_readonly :your_field_name
end
滥情哥ㄟ 2024-08-14 03:11:21

这是我对类似问题的相关解决方案 - 我们希望用户能够自行设置字段,我们在创建记录时不需要它们,但我们不希望它们在设置后被更改。

  validate :forbid_changing_some_field, on: :update

  def forbid_changing_some_field
    return unless some_field_changed?
    return if some_field_was.nil?

    self.some_field = some_field_was
    errors.add(:some_field, 'can not be changed!')
  end

但令我惊讶的是,update_attribute 仍然有效,它绕过了验证。没什么大不了的,因为记录的更新在实践中是大量分配的 - 但我在测试中指出了这一点以使其清楚。这是一些测试。

    describe 'forbids changing some field once set' do
      let(:initial_some_field) { 'initial some field value' }
      it 'defaults as nil' do
        expect(record.some_field).to be nil
      end

      it 'can be set' do
        expect {
          record.update_attribute(:some_field, initial_some_field)
        }.to change {
          record.some_field
        }.from(nil).to(initial_some_field)
      end

      context 'once it is set' do
        before do
          record.update_attribute(:some_field, initial_some_field)
        end

        it 'makes the record invalid if changed' do
          record.some_field = 'new value'
          expect(record).not_to be_valid
        end

        it 'does not change in mass update' do
          expect {
            record.update_attributes(some_field: 'new value')
          }.not_to change {
            record.some_field
          }.from(initial_some_field)
        end

        it 'DOES change in update_attribute!! (skips validations' do
          expect {
            record.update_attribute(:some_field, 'other new value')
          }.to change {
            record.some_field
          }.from(initial_some_field).to('other new value')
        end
      end
    end

Here's my related solution to a similar problem - we have fields that we want a user to be able to set themselves, we don't require them on creation of the record, but we do NOT want to them be changed once they are set.

  validate :forbid_changing_some_field, on: :update

  def forbid_changing_some_field
    return unless some_field_changed?
    return if some_field_was.nil?

    self.some_field = some_field_was
    errors.add(:some_field, 'can not be changed!')
  end

The thing that surprised me, though, was that update_attribute still works, it bypasses the validations. Not a huge deal, since updates to the record are mass assigned in practice - but I called that out in the tests to make it clear. Here's some tests for it.

    describe 'forbids changing some field once set' do
      let(:initial_some_field) { 'initial some field value' }
      it 'defaults as nil' do
        expect(record.some_field).to be nil
      end

      it 'can be set' do
        expect {
          record.update_attribute(:some_field, initial_some_field)
        }.to change {
          record.some_field
        }.from(nil).to(initial_some_field)
      end

      context 'once it is set' do
        before do
          record.update_attribute(:some_field, initial_some_field)
        end

        it 'makes the record invalid if changed' do
          record.some_field = 'new value'
          expect(record).not_to be_valid
        end

        it 'does not change in mass update' do
          expect {
            record.update_attributes(some_field: 'new value')
          }.not_to change {
            record.some_field
          }.from(initial_some_field)
        end

        it 'DOES change in update_attribute!! (skips validations' do
          expect {
            record.update_attribute(:some_field, 'other new value')
          }.to change {
            record.some_field
          }.from(initial_some_field).to('other new value')
        end
      end
    end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文