Home > Enterprise >  Update column if has_many field exists
Update column if has_many field exists

Time:09-08

I have two tables business_hours and working_hours.

The models:

class BusinessHour < ApplicationRecord
  has_many :working_hours, class_name: "WorkingHour"
  belongs_to :organization
  accepts_nested_attributes_for(:working_hours, update_only: true)
end


class WorkingHour < ApplicationRecord
  belongs_to :business_hour

  validates :day, inclusion: { in: %w(mon tue wed thu fri sat sun) }

  validate :validate_day, on: :create

  def validate_day
    if business_hour.working_hours.where(day: self.day).exists?
      errors.add(:day, "has already been added")
    end
  end
end

The controller:

class Api::V1::Admin::BusinessHoursController < Api::BaseController 
  def update
    @organization.build_business_hours unless @organization.business_hours
    if @organization.business_hours.update(business_hour_params)
      render status: :ok,
        json: { notice: I18n.t("resource.update", resource_name: "Organization") }
    else
      render status: :unprocessable_entity, json: { errors: @organization.business_hours.errors.full_messages }
    end
  end

  private

    def business_hour_params
      params.require(:business_hours).permit(
        :enabled, :away_message, working_hours_attributes: [:day, :start_time, :end_time]
      )
    end
end

When the business_hours is updated , I'm trying to update the working_hours as well.

The required behaviour is that, the working_hours should be created with day field from mon to friday and each business_hour will have 7 working_hours entry. For example, if a working_hour with day as "mon" already exists for a business_hour, when the update method in controller is called , only the start_time and end_time needs to be updated for the particular working_hour. How to go about this?

Request body example:

{
    "business_hours": {
        "enabled": true,
        "away_message": "Hello",
        "working_hours_attributes": [{
            "day": "mon",
            "start_time": "Tue, 06 Sep 2022 10:07:21.771116000 UTC  00:00",
            "end_time": "Tue, 06 Sep 2022 10:07:21.771116000 UTC  00:00"
        }]
    }
}

CodePudding user response:

As said on the comment:

Well, nested attributes can be updated by using "id" key, if your frontend doesn't have this info you could treat the parameters to convert day: 'mon' to id: id by storing your 'working_hours' into a key-value pair, ..., I don´t think there is a better way of doing it without using this middleware between your update and your permitted parameters

class Api::V1::Admin::BusinessHoursController < Api::BaseController 
  def update
    @organization.build_business_hours unless @organization.business_hours
    if @organization.business_hours.update(update_business_hour_params)
      render status: :ok,
        json: { notice: I18n.t("resource.update", resource_name: "Organization") }
    else
      render status: :unprocessable_entity, json: { errors: @organization.business_hours.errors.full_messages }
    end
  end

  private

  def business_hour_params
    params.require(:business_hours).permit(
      :enabled, :away_message, working_hours_attributes: [:day, :start_time, :end_time]
    )
  end

  # THIS HASN'T BEEN TESTED, USE IT AS AN EXAMPLE
  def update_business_hour_params
    update_business_hour_params = business_hour_params
    update_business_hour_params[:working_hours_attributes].each do |working_hour_parameters|
      working_hour_parameters[:id] = working_hours_day_id_pair[working_hour_parameters.delete(:day)] # Retrieves the id from the day
    end

    update_business_hour_params
  end

  def working_hours_day_id_pair
    @working_hours_day_id_pair ||= @organization.business_hours.working_hours.pluck(:day, :id).to_h
  end
end

as said, this is an example, I could not test the code, but that's the idea

as your attributes is already update_only, you should be good to go, hope this helps you

  • Related