These are chat archives for dry-rb/chat

24th
Jun 2018
Jaromír Červenka
@Cervajz
Jun 24 2018 13:33
@timriley Cool :)
Jaromír Červenka
@Cervajz
Jun 24 2018 15:44

I am trying to do a validation, where I check existence of another record (model), but I am not sure if the way is correct, it does not seem right to me:

module SupportTickets
  CreateSchema = Dry::Validation.Schema(ApplicationSchema) do
    required(:user_id).filled(:int?, exists?: :id)
    required(:subject).filled(:str?)
    required(:message).filled(:str?)
    required(:priority).filled(:bool?)

    optional(:machine_ids).each(:int?)

    # TODO: Decouple model from the validation
    validate(exists?: :machine_ids) do |machine_ids|
      if machine_ids.present?
        Machine.where(id: machine_ids).count == machine_ids.count
      else
        true
      end
    end
  end
end

Have anyone solved similar user-case? Where the input is array of IDs of another model as I am trying to make relationship

I know that AR takes care of that with belongs_to / has_many associations automatically but I'd like to have it on the validation layer, to make it more explicit
Jaromír Červenka
@Cervajz
Jun 24 2018 15:49
I've solved it for the user_id in the ApplicationSchema like this:
class ApplicationSchema < Dry::Validation::Schema
  configure do |config|
    option :record
    config.messages_file = 'config/locales/validations.yml'
  end

   ...
  def exists?(attr_name, value)
    record.class.where(attr_name.to_sym => value).count.positive?
  end
   ...
end
CreateSchema.with(record: User.new).call(input)
Which I don't like as well, but the dependency is at least more visible like this
Jaromír Červenka
@Cervajz
Jun 24 2018 15:58
Or maybe like this? :)
# app/schemas/support_tickets/create_schema.rb
module SupportTickets
  CreateSchema = Dry::Validation.Schema(ApplicationSchema) do
    configure do
      option :machine_repository
      option :user_repository
    end

    required(:user_id).filled(:int?)
    required(:subject).filled(:str?)
    required(:message).filled(:str?)
    required(:priority).filled(:bool?)

    optional(:machine_ids).each(:int?)

    validate(exists?: :machine_ids) do |machine_ids|
      if machine_ids.present?
        machine_repository.where(id: machine_ids).count == machine_ids.count
      else
        true
      end
    end

    validate(exists?: :user_id) do |user_id|
      user_repository.find_by(id: user_id).present?
    end
  end
end


# app/transactions/support_tickets/create.rb:14
def validate_input(input)
  validation = CreateSchema.with(user_repository: User, machine_repository: Machine).call(input)
  validation.success? ? Success(input) : Failure(validation.errors)
end
That makes probably more sense for this specific use case
Jaromír Červenka
@Cervajz
Jun 24 2018 16:12
@timriley Just noticed small typo at http://dry-rb.org/gems/dry-transaction/around-steps/ registe => register