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'
toid: 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