Validate request_time and delivery_time to be greater than 24 hours, with different models

5

From the current time, I need to validate that it is greater than 24 hours:

  • hora_pedido is start time.
  • hora_entrega is final time.

From the parent model, there is an attribute called hora_pedido ; model:

class Reunion < ApplicationRecord

 #maestro de detalle 
 has_many :detalles_reuniones, :dependent => :destroy
 accepts_nested_attributes_for :detalles_reuniones, allow_destroy: true

 def detalles_reuniones_for_form
   collection = detalles_reuniones.where(reunion_id: id)
   collection.any? ? collection : detalles_reuniones.build
 end


     #El metodo que asigna los valores
    before_validation :asignar_valores_por_defecto_reunion

   def asignar_valores_por_defecto_reunion
    Time.zone = "America/Bogota"
   self.hora_pedido = Time.zone.now.strftime("%Y-%m-%d-%H:%M:%S" )
 end

From the child model, there is an attribute called hora_entrega ; class model

class DetalleReunion < ApplicationRecord

    #Asociaccion por maestro de detalle
    belongs_to :reunion, optional: true

   validate :validar_horas 

   def validar_horas
     if ( hora_entrega - ( 60 * 60 * 24 ) ) >= ( reunion.hora_pedido )
     # Código cuando se cumple la condición
     else
      errors.add(:hora_entrega," La entrega debe ser mayor a 24  horas  ")
    end
   end       
end

The two attributes are of type Time :

  • hora_pedido = Time
  • hora_entrega = Time

It is a master detail, are two forms filled at the same time then in the parent table there is an attribute that is hora_pedido , this would be the current time and in the daughter table there is an attribute that is hora_entrega is the time , to define the one that is greater than 24 hours, the parent table is called reunion and the daughter table detalle_reunion .

I've already updated the whole code :

LOG

  Started POST "/reuniones" for 200.47.156.216 at 2017-06-09 15:38:30 +0000
  Cannot render console from 200.47.156.216! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
  Processing by ReunionesController#create as HTML
   Parameters: {"utf8"=>"✓", "authenticity_token"=>"NXxV3OeCmrzYCMB6ZoVxWuFArqnjgpvjAnFHA84NVOwFd3hRehH0TtWPjfICry/4Nhmpi+zkL6cgmsEA2wIrHw==", 
   "reunion"=>{"detalles_reuniones_attributes"=>{"0"=>{"
    producto_id"=>"", 
    "cantidad"=>"",
    "valor"=>"", 
    "hora_entrega(1i)"=>"2017", 
    "hora_entrega(2i)"=>"6", 
    "hora_entrega(3i)"=>"9", 
    "hora_entrega(4i)"=>"03", 
    "hora_entrega(5i)"=>"38", 
    "_destroy"=>"false"}}, 
    "subtotal"=>"", 
    "hora_inicio(1i)"=>"2017", 
    "hora_inicio(2i)"=>"6", 
    "hora_inicio(3i)"=>"9", 
    "hora_inicio(4i)"=>"10", 
    "hora_inicio(5i)"=>"38", 
    "hora_final(1i)"=>"2017", 
    "hora_final(2i)"=>"6", 
    "hora_final(3i)"=>"9", 
    "hora_final(4i)"=>"10", 
    "hora_final(5i)"=>"38", 
    "fecha_entrega"=>"09/06/2017", 
    "planta_id"=>"", 
    "centro_costo_fullname"=>"", 
    "ubicacion"=>"", 
    "observacion"=>""}, 
    "commit"=>"Crear Reunion"}
  (0.1ms)  begin transaction
  (0.1ms)  rollback transaction
 Rendering reuniones/new.html.erb within layouts/application
 Producto Load (0.2ms)  SELECT "productos".* FROM "productos"
 Rendered reuniones/_detalle_reunion_fields.html.erb (8.1ms) [cache miss]
 CACHE Producto Load (0.0ms)  SELECT "productos".* FROM "productos"
 Rendered reuniones/_detalle_reunion_fields.html.erb (6.6ms) [cache miss]
 Planta Load (0.1ms)  SELECT "plantas".* FROM "plantas"
 Rendered reuniones/_form.html.erb (30.7ms) [cache miss]
 Rendered reuniones/new.html.erb within layouts/application (31.8ms)
 Rendered layouts/_navigation_links.html.erb (0.7ms) [cache miss]
 Rendered layouts/_navigation.html.erb (1.9ms) [cache miss]
 Rendered layouts/_messages.html.erb (0.5ms) [cache miss]
 Completed 200 OK in 200ms (Views: 187.0ms | ActiveRecord: 0.5ms)

*** ignore the other attributes not necessary ****

create_table "detalles_reuniones", force: :cascade do |t|
  t.time "hora_entrega"
  t.integer "cantidad"
  t.integer "reunion_id"
  t.integer "producto_id"
  t.integer "evento_interno_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer "valor"
  t.index ["evento_interno_id"], name: " 
  index_detalles_reuniones_on_evento_interno_id"
  t.index ["producto_id"], name: "index_detalles_reuniones_on_producto_id"
  t.index ["reunion_id"], name: "index_detalles_reuniones_on_reunion_id"
end

create_table "reuniones", force: :cascade do |t|
  t.time "hora_pedido"
  t.date "fecha_pedido"
  t.time "hora_inicio"
  t.time "hora_final"
  t.date "fecha_entrega"
  t.string "observacion"
  t.integer "subtotal"
  t.integer "planta_id"
  t.integer "centro_costo_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.string "ubicacion"
  t.index ["centro_costo_id"], name: "index_reuniones_on_centro_costo_id"
  t.index ["planta_id"], name: "index_reuniones_on_planta_id"
end
    
asked by juan gomez 08.06.2017 в 16:44
source

1 answer

1

There are different points that should be corrected in your code:

  • The validation is in the wrong model, since you want to validate hora_entrega , which is part of the DetalleRuenion model, therefore you should move the validation to that model.

  • Use the appropriate callback for validation; now you are using before_save to assign hora_pedido , so when validating hora_entrega , that field is empty (i.e. nil ). To work, use the callback before_validation .

  • Add the appropriate ratio (i.e. has_many ) in your model Reunion .

  • The names of your models do not follow the ActiveRecord conventions, so you must change the name of your models or, specify the appropriate table in them using self.table_name (in your case I recommend the latter).

  • In the validar_horas method you are not including any action after the if (which I think is correct since it is a validation) 1 , so I recommend using unless 2 instead and thus avoid leaving the if empty.

  • Considering the previous points, so you should see your models and your controller:

    app / models / reunion.rb:

    class Reunion < ApplicationRecord 
      self.table_name = 'reuniones' 
      before_validation :asignar_valores_por_defecto_reunion
    
      has_many :detalles_reuniones
    
      def asignar_valores_por_defecto_reunion
        Time.zone = "America/Bogota"
        self.hora_pedido = Time.zone.now.strftime("%Y-%m-%d-%H:%M:%S" )
      end
    end
    

    app / models / detal_reunion.rb:

    class DetalleReunion < ApplicationRecord
      self.table_name = 'detalles_reuniones' 
    
      validate :validar_horas
      belongs_to :reunion
    
      def validar_horas
        unless hora_entrega - (60 * 60 * 24) >= reunion.hora_pedido
          errors.add(:hora_entrega, "La entrega debe ser mayor a 24  horas")
        end
      end 
    end
    

    app / controllers / details_reuniones_controller.rb

    class DetallesReunionesController < ApplicationController 
      before_action :set_detalle_reunion, only: [:show, :edit, :update, :destroy] 
    
      def index 
        @detalles_reuniones = DetalleReunion.all 
      end 
    
      def show 
      end 
    
      def new 
        @detalle_reunion = DetalleReunion.new 
      end 
    
      def edit 
      end 
    
      def create 
        @detalle_reunion = DetalleReunion.new(detalle_reunion_params) 
    
        respond_to do |format| 
          if @detalle_reunion.save 
            format.html { redirect_to @detalle_reunion, notice: 'Detalle reunion was successfully created.' } 
            format.json { render :show, status: :created, location: @detalle_reunion } 
          else 
            format.html { render :new } 
            format.json { render json: @detalle_reunion.errors, status: :unprocessable_entity } 
          end 
        end 
      end 
    
      def update 
        respond_to do |format| 
          if @detalle_reunion.update(detalle_reunion_params) 
            format.html { redirect_to @detalle_reunion, notice: 'Detalle reunion was successfully updated.' } 
            format.json { render :show, status: :ok, location: @detalle_reunion } 
          else 
            format.html { render :edit } 
            format.json { render json: @detalle_reunion.errors, status: :unprocessable_entity } 
          end 
        end 
      end 
    
      def destroy 
        @detalle_reunion.destroy 
    
        respond_to do |format| 
          format.html { redirect_to detalles_reuniones_url, notice: 'Detalle reunion was successfully destroyed.' } 
          format.json { head :no_content } 
        end 
      end 
    
      private 
      def set_detalle_reunion 
        @detalle_reunion = DetalleReunion.find(params[:id]) 
      end 
    
      def detalle_reunion_params 
        params.require(:reunion)
              .permit(detalles_reuniones_attributes: [:hora_entrega, :cantidad, :producto_id, :valor, :evento_interno_id])
      end 
    end
    

    1 This does not generate any errors, but for readability it is better to avoid this programming style .

    2 If you do not like unless , you can also choose to change the logic of if :

    if hora_entrega - (60 * 60 * 24) < reunion.hora_pedido
      errors.add(:hora_entrega, "La entrega debe ser mayor a 24  horas")
    end
    
        
    answered by 08.06.2017 / 17:17
    source