Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
class DailyActiveUsersData
include ActiveModel::Model
attr_accessor :app_id, :ad_type, :first_request_date
validates :app_id, :ad_type, :first_request_date, presence: true
validates :app_id, numericality: { greater_than: 0 }
validates :ad_type, inclusion: { in: [:android, :ios] }
validates :first_request_date, date: true
end
DailyActiveUsersData.new(app_id: 1, ad_type: :ios, first_request_date: Time.now)
data = DailyActiveUsersData.new
data.app_id = 1
data.ad_type = :ios
data.validate!
class DailyActiveUsersData
include ActiveModel::Model
def self.new!(attrs)
object = new(attrs)
object.validate!
object
end
end
class DailyActiveUsersData
include ActiveModel::Model
def initialize(attrs)
super(attrs)
validate!
end
end
# если передать не корректное значение, получим ошибку
Types::PlatformId['windows']
# => Dry::Types::ConstraintError
Зачем мы разрешаем создавать объекты с невалидным состоянием?
order.client_id записано Types::Strict::Integer.constrained(gt: 0) не дает нам никаких гарантий, что у заказа есть Client, потому что не факт, что у нас есть клиент с таким id. То есть типами мы все равно не избавимся от невалидных объектов. // Код на Rust
extern crate uuid;
use uuid::Uuid;
const IOS: i32 = 1;
const ANDROID: i32 = 2;
const FIRE_OS: i32 = 3;
enum Platform {
IOS,
ANDROID,
FIRE_OS,
}
struct DailyActiveUsersData {
app_id: i32,
country_id: i32,
user_id: i32,
platform_id: Platform,
ad_id: Uuid,
first_request_date: &'static str,
}
fn main() {
let uuid = Uuid::parse_str("6a2f41a3-c54c-fce8-32d2-0324e1c32e22").unwrap();
let data = DailyActiveUsersData {
app_id: 1,
country_id: 2,
user_id: 3,
platform_id: Platform::IOS,
ad_id: uuid,
first_request_date: "2018-12-16",
};
println!("Data {:?}", data);
}
# Код на Ruby (я обожаю Ruby и пишу на нем каждый день, и мне кажется Ruby не об этом)
require 'dry-types'
require 'dry-struct'
module Types
include Dry::Types.module
PLATFORMS = {
'android' => 1,
'fire_os' => 2,
'ios' => 3
}.freeze
UUID_REGEXP = /[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/
ENTITY_ID = Types::Strict::Integer.constrained(gt: 0)
PLATFORM_ID = Types::Strict::Integer.enum(PLATFORMS.invert)
UUID = Types::Strict::String.constrained(format: UUID_REGEXP)
ZERO = Types.Constant(0)
end
class DailyActiveUsersData < Dry::Struct
attribute :app_id, Types::ENTITY_ID
attribute :country_id, Types::ENTITY_ID
attribute :user_id, Types::ENTITY_ID
attribute :platform_id, Types::PLATFORM_ID
attribute :ad_id, Types::UUID
attribute :first_request_date, Types::Strict::Date
end
data = DailyActiveUsersData.new(
app_id: 1,
country_id: 2,
user_id: 3,
platform_id: 1,
ad_id: '6a2f41a3-c54c-fce8-32d2-0324e1c32e22',
first_request_date: Date.today
)
puts data
1. Потому что это нам требуется для решения наших задач. Например при создании объекта и для возвращения ошибок валидации. Создается объект, проходит его валидация, если объект не валиден, то мы возвращаем невалидный объект с ошибками в контроллер и рендер формы.
Из данных объекта мы проставляем значения в полях, из объекта ошибок мы выводим ошибки.
Т.е. например если бы наш объект Order не мог бы находиться в невалидном состоянии, нам бы пришлось создать еще какой-то класс NonValidOrder и периодически мы рендерили бы форму/json из Order, а периодически из NonValidOrder, и пришлось бы еще делать какие-то механизмы превращения одного в другое. Зачем, если мы всегда можно вызывать метод valid? везде где оно требуется.
respond_to?RoR не есть Ruby
Так этот вариант как раз для тех, для кого RoR не существует)Значит, я ещё не созрел для того, чтобы это понять
Я имел в виду что RoR для меня не существует, а Ruby существует, а то, что не существует не может быть тем, что существуетRoR не есть RubyКак такое может быть? Если не Ruby, то это уже Grails, Sails.js или что-нибудь ещё)
Решаем проблемы типов данных в Ruby или Make data reliable again