Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

404
Vistas
¿Manera limpia de implementar la validación en rutas no crudas en Rails?

¿Cómo implementa la validación en rutas NO CRUD? Por ejemplo, hay una ruta para buscar recipes . Acepta parámetros de term (para búsqueda), sort , page , etc.

¿Cuál es la mejor manera de hacer esto en Rails?

La solución más sencilla sería validar todas estas cosas usando el montón de expresiones if-else en el controlador, pero estoy buscando algo más limpio y más fácil para la extensión y el mantenimiento.

terminé con lo siguiente

 class RequestValidation attr_reader :validators attr_reader :errors def initialize @validators = [] @errors = [] end def add_validator(validator) @validators << validator end def validate @validators.each do |validator| validator.validate @errors += validator.errors end end def valid? validate errors.empty? end end

Ejemplo de clase de validador

 class SortValidator < Validator VALID_SORT_FIELD = [:created_at, :rate, :total_time] VALID_SORT_DIRECTIONS = [:asc, :desc] def validate return unless param valid = true begin sort = param.to_unsafe_h if sort.size == 1 k = sort.keys[0].to_sym v = sort.values[0].to_sym valid = VALID_SORT_FIELD.include?(k) && VALID_SORT_DIRECTIONS.include?(v) else valid = false end rescue => ex valid = false end @errors << "Sort parameter invalid" unless valid end def is_valid? !errors.empty? end end

Entonces, RequestValidation es como una clase de constructor/contenedor para todos los validadores. Y luego, en el controlador:

 validation = RequestValidation.new validation.add_validator(RecipesValidators::SortValidator.new(params[:sort])) validation.validate if validation.errors.empty?

De esta manera, cuando se requiere una nueva validación, solo necesitamos crear una nueva clase de Validador y agregarla para solicitar la validación.

Dado que me tomé una pausa de Rails durante varios años, existen dudas sobre si este código es limpio y ordenado y de acuerdo con los principios de Ruby.

¿O hay un mejor camino?

Gracias por adelantado

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Hoy en día iría poniendo algún contrato y una estructura fuertemente tipada entre el controlador y la base de datos.

Algo como:

 # obtain an instance of RecipeSearchParamsContract def contract @contract ||= SomeValidationContract.new end # obtain an instance of a coercing struct def input MyStruct.new(params) end def query MyQuery.new end def your_action if contract.call(params).success? render query.call(input) end end

Entonces estás separando completamente todas las preocupaciones. Buenas librerías para basar tu código son dry-validator y dry-struct , con las cuales puedes generar un contrato de la siguiente manera:

 class SearchParamsContract < Dry::Validation::Contract params do optional(:sort).hash(max_size?: 1) do optional(:rate).value(included_in?: %w[asc desc]) optional(:created_at).value(included_in?: %w[asc desc]) optional(:total_time).value(included_in?: %w[asc desc]) end optional(:page).value(:integer) optional(:term).filled(:string) end end

Usando esto, la estructura forzada y validada está disponible en el resultado mismo, por lo que puede encadenar todo y usar la coincidencia de patrones estructurales para obtener un código increíble y muy rubí (sin rieles extra)

 def search case contract.call(params) in Success(input) @recipes = query.call(input) else render :error end end
over 4 years ago · Santiago Trujillo Denunciar

0

La solución aquí nunca fue realmente un validador personalizado; en su lugar, debe crear una clase como un modelo o un objeto de formulario para encapsular las validaciones y los datos. El hecho de que su acción no persista no significa que no pueda usar un modelo para representar datos y lógica empresarial.

 class RecipeSearch include ActiveModel::Model include ActiveModel::Attributes attribute :query, :string attribute :sort_by, :string # ... validates :query, length: { minimum: 5 } validates :sort_by, in: ['newest', 'quickest', 'cheapest'] # ... # @todo apply filters to Recipe and return collection def perform # ... end end

Esto le permite agregar validaciones y lógica. Y pasarlo a formularios:

 <%= form_with(model: local_assigns(:recipe_seach) || RecipeSearch.new) do |f| %> # ... <% end %>

También es un error pensar que la búsqueda no puede ser parte de CRUD. Después de todo, es solo lectura con filtros aplicados. Si realmente necesita una vista separada de su índice normal, entonces cree una acción de búsqueda separada, pero no es realmente una necesidad.

 class RecipesController def index @recipe_search = RecipeSearch.new(search_params) @recipes = @recipe_search.perform end private def search_params params.fetch(:recipe_search, {}) .permit(:query, :sort_by) end end
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda