Spec-Zone.ru › Ruby on Rails 8.0

модуль ActiveRecord::Attributes::ClassMethods

Атрибуты Active Record

Общедоступные методы экземпляров

attribute(name, cast_type = nil, **options) Показать исходный код
# File activerecord/lib/active_record/attributes.rb, line 13
      

Определяет атрибут с типом для этой модели. Он переопределит тип существующих атрибутов при необходимости. Это позволяет контролировать, как значения преобразуются в SQL и из SQL при присвоении модели. Это также изменяет поведение значений, передаваемых в ActiveRecord::Base.where. Это позволит вам использовать ваши предметные области в Active Record, не полагаясь на детали реализации или модификацию класса.

name Название методов для определения методов атрибутов и столбец, в который будет сохранено это значение.

cast_type Символ, такой как :string или :integer, или объект типа, используемый для этого атрибута. Если этот параметр не передан, будет использоваться ранее определённый тип (если таковой имеется). В противном случае тип будет ActiveModel::Type::Value. Дополнительную информацию о предоставлении пользовательских объектов типа см. в примерах ниже.

Параметры

Принимаются следующие параметры:

default Значение по умолчанию, используемое, когда значение не предоставлено. Если этот параметр не передан, будет использовано значение по умолчанию, определённое в суперклассе или в схеме (если таковое имеется). В противном случае значение по умолчанию будет nil.

array (только PostgreSQL) указывает, что тип должен быть массивом (см. примеры ниже).

range (только PostgreSQL) указывает, что тип должен быть диапазоном (см. примеры ниже).

При использовании символа для cast_type, дополнительные параметры передаются в конструктор объекта типа.

Примеры

Тип, обнаруженный Active Record, может быть переопределён.

# db/schema.rb
create_table :store_listings, force: true do |t|
  t.decimal :price_in_cents
end

# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
end

store_listing = StoreListing.new(price_in_cents: '10.1')

# before
store_listing.price_in_cents # => BigDecimal(10.1)

class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, :integer
end

# after
store_listing.price_in_cents # => 10

Также может быть предоставлено значение по умолчанию.

# db/schema.rb
create_table :store_listings, force: true do |t|
  t.string :my_string, default: "original default"
end

StoreListing.new.my_string # => "original default"

# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
  attribute :my_string, :string, default: "new default"
end

StoreListing.new.my_string # => "new default"

class Product < ActiveRecord::Base
  attribute :my_default_proc, :datetime, default: -> { Time.now }
end

Product.new.my_default_proc # => 2015-05-30 11:04:48 -0600
sleep 1
Product.new.my_default_proc # => 2015-05-30 11:04:49 -0600

Атрибуты не обязаны быть поддерживаемыми столбцом базы данных.

# app/models/my_model.rb
class MyModel < ActiveRecord::Base
  attribute :my_string, :string
  attribute :my_int_array, :integer, array: true
  attribute :my_float_range, :float, range: true
end

model = MyModel.new(
  my_string: "string",
  my_int_array: ["1", "2", "3"],
  my_float_range: "[1,3.5]",
)
model.attributes
# =>
  {
    my_string: "string",
    my_int_array: [1, 2, 3],
    my_float_range: 1.0..3.5
  }

Передача параметров в конструктор типа

# app/models/my_model.rb
class MyModel < ActiveRecord::Base
  attribute :small_int, :integer, limit: 2
end

MyModel.create(small_int: 65537)
# => Error: 65537 is out of range for the limit of two bytes

Создание пользовательских типов

Пользователи также могут определять свои собственные пользовательские типы, если они реагируют на методы, определённые в типе значения. Метод deserialize или cast будет вызываться в вашем объекте типа с исходными данными из базы данных или из контроллеров. См. ActiveModel::Type::Value для ожидаемой API. Рекомендуется, чтобы ваши объекты типа наследовали от существующего типа или от ActiveRecord::Type::Value

class PriceType < ActiveRecord::Type::Integer
  def cast(value)
    if !value.kind_of?(Numeric) && value.include?('$')
      price_in_dollars = value.gsub(/\$/, '').to_f
      super(price_in_dollars * 100)
    else
      super
    end
  end
end

# config/initializers/types.rb
ActiveRecord::Type.register(:price, PriceType)

# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, :price
end

store_listing = StoreListing.new(price_in_cents: '$10.00')
store_listing.price_in_cents # => 1000

Для получения более подробной информации о создании пользовательских типов, см. документацию по ActiveModel::Type::Value. Для получения более подробной информации о регистрации типов для ссылки по символу см. ActiveRecord::Type.register. Вы также можете напрямую передать объект типа вместо символа.

Запросы

Когда вызывается ActiveRecord::Base.where, он будет использовать тип, определенный классом модели, для преобразования значения в SQL, вызывая serialize в вашем объекте типа. Например:

class Money < Struct.new(:amount, :currency)
end

class PriceType < ActiveRecord::Type::Value
  def initialize(currency_converter:)
    @currency_converter = currency_converter
  end

  # value will be the result of +deserialize+ or
  # +cast+. Assumed to be an instance of +Money+ in
  # this case.
  def serialize(value)
    value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
    value_in_bitcoins.amount
  end
end

# config/initializers/types.rb
ActiveRecord::Type.register(:price, PriceType)

# app/models/product.rb
class Product < ActiveRecord::Base
  currency_converter = ConversionRatesFromTheInternet.new
  attribute :price_in_bitcoins, :price, currency_converter: currency_converter
end

Product.where(price_in_bitcoins: Money.new(5, "USD"))
# SELECT * FROM products WHERE price_in_bitcoins = 0.02230

Product.where(price_in_bitcoins: Money.new(5, "GBP"))
# SELECT * FROM products WHERE price_in_bitcoins = 0.03412

Отслеживание изменений

Тип атрибута получает возможность изменить способ выполнения отслеживания изменений. Методы changed? и changed_in_place? будут вызываться из ActiveModel::Dirty. См. документацию по этим методам в ActiveModel::Type::Value для получения дополнительной информации.

define_attribute( name, cast_type, default: NO_DEFAULT_PROVIDED, user_provided_default: true ) Показать исходный код
# File activerecord/lib/active_record/attributes.rb, line 231
def define_attribute(
  name,
  cast_type,
  default: NO_DEFAULT_PROVIDED,
  user_provided_default: true
)
  attribute_types[name] = cast_type
  define_default_attribute(name, default, cast_type, from_user: user_provided_default)
end

Этот API принимает только объекты типа и выполняет свою работу немедленно, а не ожидая загрузки схемы. Хотя этот метод предоставляется для использования авторам плагинов, код приложения, вероятно, должен использовать ClassMethods#attribute.

name Название определяемого атрибута. Ожидается, что это будет String.

cast_type Объект типа для использования с этим атрибутом.

default Значение по умолчанию, используемое, когда значение не предоставлено. Если этот параметр не передан, будет использоваться предыдущее значение по умолчанию (если таковое имеется). В противном случае значение по умолчанию будет nil. Также можно передать процедуру, которая будет вызываться каждый раз, когда требуется новое значение.

user_provided_default Указывает, следует ли приводить значение по умолчанию с помощью cast или deserialize.

type_for_attribute(attribute_name, &block) Показать исходный код
# File activerecord/lib/active_record/attributes.rb, line 256
      

См. ActiveModel::Attributes::ClassMethods#type_for_attribute.

Этот метод будет обращаться к базе данных и загружать схему модели при необходимости.

Защищенные методы экземпляров

reload_schema_from_cache(*) Показать исходный код
# File activerecord/lib/active_record/attributes.rb, line 268
def reload_schema_from_cache(*)
  reset_default_attributes!
  super
end
Вызов метода суперкласса

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API