如何在查询中映射ID

时间:2019-03-06 09:57:48

标签: ruby-on-rails ruby

我有卡车和乘员组模型,卡车has_many :crews。在复选框的前端,我选择卡车ID并将其发送到我的控制器。我只需要销毁没有人员的卡车。我现在所拥有的:

# 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

但是它非常复杂,我想在查询中使其更好。有人可以帮助我吗?

我认为应该是这样的

  • 选择所有不能删除的人(当然是那些 id来找我们)
  • 从传入ID的常规列表中减去它们
  • 删除保留在常规列表中

我不知道该怎么做:

a = current_company.trucks.where(id: params[:ids])
b = current_company.trucks.includes(:crews).where(truck.crews.map(&:id))
a = a - b

希望您能理解我的意思。谢谢:)

1 个答案:

答案 0 :(得分:1)

首先,您可以为“卡车”型号添加限制,以免意外删除有工作人员的卡车

has_many :crews, dependent: :restrict_with_exception 

让我们重构您的控制器代码:

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