123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::ReadonlyAttributes::ClassMethods

Relationships & Source Files
Defined in: activerecord/lib/active_record/readonly_attributes.rb

Instance Method Summary

Instance Method Details

#attr_readonly(*attributes)

::ActiveRecord::Attributes listed as readonly will be used to create a new record. Assigning a new value to a readonly attribute on a persisted record raises an error.

By setting config.active_record.raise_on_assign_to_attr_readonly to false, it will not raise. The value will change in memory, but will not be persisted on save.

Examples

class Post < {ActiveRecord::Base}
  attr_readonly :title
end

post = {Post.create!}(title: "Introducing Ruby on Rails!")
post.title = "a different title" # raises {ActiveRecord::ReadonlyAttributeError}
post.update(title: "a different title") # raises {ActiveRecord::ReadonlyAttributeError}
[ GitHub ]

  
# File 'activerecord/lib/active_record/readonly_attributes.rb', line 32

def attr_readonly(*attributes)
  attributes = attributes.map(&:to_s)
  self._attr_readonly = ActiveSupport::Ractors.make_shareable(_attr_readonly | attributes)

  # Pass the new attributes down to subclasses that hold their own copy.
  descendants.each do |subclass|
    next if subclass._attr_readonly.equal?(subclass.superclass._attr_readonly)

    subclass._attr_readonly = ActiveSupport::Ractors.make_shareable(subclass._attr_readonly | attributes)
  end

  if ActiveRecord._raise_on_assign_to_attr_readonly
    # The code generator changed, also for subclasses that already
    # generated their own writers.
    undefine_attribute_methods
    descendants.each(&:undefine_attribute_methods)
    include(HasReadonlyAttributes)
  end
end

#define_method_attribute=(canonical_name, owner:, as: canonical_name) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/readonly_attributes.rb', line 62

def define_method_attribute=(canonical_name, owner:, as: canonical_name)
  if ActiveRecord._raise_on_assign_to_attr_readonly && readonly_attribute?(canonical_name)
    ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
      canonical_name, writer: true,
    ) do |temp_method_name, attr_name_expr|
      owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: :active_record_readonly) do |batch|
        batch <<
          "def #{temp_method_name}(value)" <<
          "  unless new_record?" <<
          "    raise ActiveRecord::ReadonlyAttributeError.new(#{attr_name_expr})" <<
          "  end" <<
          "  @attributes.write_from_user(#{attr_name_expr}, value)" <<
          "end"
      end
    end
  else
    super
  end
end

#readonly_attribute?(name) ⇒ Boolean

This method is for internal use only.
[ GitHub ]

  
# File 'activerecord/lib/active_record/readonly_attributes.rb', line 57

def readonly_attribute?(name) # :nodoc:
  _attr_readonly.include?(name)
end

#readonly_attributes

Returns an array of all the attributes that have been specified as readonly.

[ GitHub ]

  
# File 'activerecord/lib/active_record/readonly_attributes.rb', line 53

def readonly_attributes
  _attr_readonly
end