user11027209
user11027209

Reputation:

How to map ids in a query

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

Answers (1)

Vasilisa
Vasilisa

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

Related Questions