Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

401
Views
¿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 answers
Answer question

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 Report

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!