Приведение типа атрибута ActiveModel перед проверкой? - PullRequest
0 голосов
/ 21 декабря 2018

Как сделать так, чтобы приведение типа атрибута происходило за до проверки ?

В этом примере я ожидаю, что атрибут delicious будет приведен к типу boolean до inclusion проверка.

require "bundler/inline"
gemfile(true) do
  ruby "2.4.3"
  source "https://rubygems.org"
  gem "activemodel", "5.2.2"
  gem "actionpack", "5.2.2"
end
require "active_model"
require "action_controller"
require "minitest/autorun"

class Fruit
  include ActiveModel::Model
  include ActiveModel::Attributes
  attr_accessor :delicious, :name
  attribute :delicious, :boolean
  validates :delicious, inclusion: { in: [false, true] }
end

class TestFruit < Minitest::Test
  def test_fruit
    params = ActionController::Parameters.new(
      delicious: '1', # rails checkboxes use strings '0' or '1'
      name: 'banana'
    ).permit!
    banana = Fruit.new(params)
    banana.validate
    assert_equal [], banana.errors.full_messages
    # Fails: ["Delicious is not included in the list"]
  end
end

Обратите внимание, что этот вопрос не имеет ничего общего с ActiveRecord.

Ответы [ 2 ]

0 голосов
/ 07 августа 2019

?

Удалить attr_accessor :delicious.attribute определит методы получения и установки.

Некоторый анализ:

attr_accessor

Методы получения и установки определены непосредственно в Fruit.

1| class Fruit
2|   attr_accessor :delicious
3| end

method = Fruit.new.method(:delicious)
method.owner # => Fruit
method.source_location # => ['/path/to/fruit.rb', 2]

attribute

Методы получения и установки определены для экземпляра анонимного модуля, который Fruit использует для поиска метода.

1| class Fruit
2|  attribute :delicious
3| end

method = Fruit.new.method(:delicious)
mod = method.owner # => #<Module:0x00007fc583da1f60>
Fruit.ancestors.include?(mod) # => true
method.source_location # => ['/path/to/active_model/attribute_methods.rb', 36]

При использовании обоих attr_accessor и attribute, Fruit вызовут более непосредственные методы получения и установки: те, которые определены как attr_accessor.

1| class Fruit
2|   attr_accessor :delicious
3|   attribute :delicious
4| end

method = Fruit.new.method(:delicious)
method.owner # => Fruit
method.source_location # => ['/path/to/fruit.rb', 2]
0 голосов
/ 21 декабря 2018

Используйте пользовательский установщик

def delicious=(value)
  self[:delicious] = case value
  when '1', 1 then true
  when '0', 0 then false
  end
end

Таким образом, вы всегда будете иметь логическое значение (или ноль).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...