Reputation:
I have Truck and Crew models, Truck has_many :crews
. On frontend-side in checkboxes I select truck ids and send them to my controller. I need to destroy only trucks which have no crews. What I have now:
# app/models/truck.rb
belongs_to :company
has_many :crews
# app/models/crew.rb
belongs_to :truck, optional: true
# trucks_controller.rb
def bulk_destroy
trucks_with_crews = []
current_company.trucks.where(id: params[:ids]).find_each do |truck|
if truck.crews.exists?
trucks_with_crews << truck
next
end
truck.destroy
end
if trucks_with_crews.empty?
head :no_content
else
message = []
trucks_with_crews.each_with_object([]) { |x| message << x.name }
render json: { message: "Trucks: '#{message.join(', ')}' can't be deleted because used by crews." }, status: :unprocessable_entity
end
end
But it's very overcomplicated, and I want to make it better in the query. Anyone can help me?
I think it should be something like:
I don't know exactly how to do it:
a = current_company.trucks.where(id: params[:ids])
b = current_company.trucks.includes(:crews).where(truck.crews.map(&:id))
a = a - b
I hope you understand what I mean. Thanks :)
Upvotes: 0
Views: 68
Reputation: 4640
At first you can add a restriction to Truck model to not delete accidentally a truck with crew
has_many :crews, dependent: :restrict_with_exception
Let's refactor your controller code:
def bulk_destroy
# let find truck which should be deleted
trucks_wo_crew = current_company.trucks.includes(:crews)
.where(id: params[:ids]).where(crews: { id: nil })
# and delete them
trucks_wo_crew.destroy_all
# if we search by id after deletion we'll get trucks with crew,
# because we already deleted other.
# We can get only names, since we don't need other info
trucks_with_crew = current_company.trucks.where(id: params[:ids]).pluck(:name)
return head :no_content if trucks_with_crew.empty?
render json: { message: "Trucks: '#{trucks_with_crew.join(', ')}' can't be deleted because used by crews." }, status: :unprocessable_entity
end
Upvotes: 1