Ruby on rails 是否可以删除带有内部联接条件的_all?

Ruby on rails 是否可以删除带有内部联接条件的_all?,ruby-on-rails,inner-join,Ruby On Rails,Inner Join,我需要一次删除很多记录,并且我需要根据另一个模型中的条件进行删除,该模型由“属于”关系关联。我知道我可以循环检查每个条件,但对于我的大记录集来说,这会花费很长时间,因为对于每个“属于”它都会进行单独的查询 这里有一个例子。我有一个“产品”模型,它“属于”一个“艺术家”,可以说艺术家有一个属性“被禁用” 如果我想删除所有属于残疾艺术家的产品,我希望能够执行以下操作: Product.delete_all(:joins => :artist, :conditions => ["artis

我需要一次删除很多记录,并且我需要根据另一个模型中的条件进行删除,该模型由“属于”关系关联。我知道我可以循环检查每个条件,但对于我的大记录集来说,这会花费很长时间,因为对于每个“属于”它都会进行单独的查询

这里有一个例子。我有一个“产品”模型,它“属于”一个“艺术家”,可以说艺术家有一个属性“被禁用”

如果我想删除所有属于残疾艺术家的产品,我希望能够执行以下操作:

Product.delete_all(:joins => :artist, :conditions => ["artists.is_disabled = ?", true])

这可能吗?我以前直接在SQL中这样做过,但不确定是否可以通过rails来实现。

问题在于delete\u all会丢弃所有连接信息(这是正确的)。您要做的是将其捕获为内部选择

如果您使用的是Rails 3,那么您可以创建一个范围来满足您的需求:

class Product < ActiveRecord::Base
  scope :with_disabled_artist, lambda {
    where("product_id IN (#{select("product_id").joins(:artist).where("artist.is_disabled = TRUE").to_sql})")
  }
end
您也可以内联使用相同的查询,但这不是很优雅(或自我记录):


如果您使用的是Rails 2,则无法执行上述操作。另一种方法是在find方法中使用joins子句,并对每个项调用delete

    TellerLocationWidget.find(:all, :joins => [:widget, :teller_location],
      :conditions => {:widgets => {:alt_id => params['alt_id']},
      :retailer_locations => {:id => @teller_location.id}}).each do |loc|
        loc.delete
    end
在Rails 4中(我在4.2上进行了测试),您几乎可以按照OP最初的要求进行操作

Application.joins(:vacancy).where(vacancies: {status: 'draft'}).delete_all
将给予

DELETE FROM `applications` WHERE `applications`.`id` IN (SELECT id FROM (SELECT `applications`.`id` FROM `applications` INNER JOIN `vacancies` ON `vacancies`.`id` = `applications`.`vacancy_id` WHERE `vacancies`.`status` = 'draft') __active_record_temp)

如何“正确地”移除连接?通常需要连接条件来限制要删除的记录。我认为最糟糕的是,它是以静默的方式进行的,这可能会非常令人惊讶。我的意思是,无论如何,在SQL中都不能像这样进行连接-删除操作,因此这样做是正确的。我很确定Rails的更高版本也会执行子查询。我不确定这是否是最好的方法,因为当它实际上是子查询时,它会使它看起来像联接中的底层查询。@gcastro这是不真实的——在mysql中,至少有一个可以用join语句绝对执行delete。这将导致不相同且不可缩放的单个删除。您应该能够在Rails 2中使用命名作用域。虽然这在PostgreSQL上很好,但在MySQL服务器上速度非常慢。当心。
Application.joins(:vacancy).where(vacancies: {status: 'draft'}).delete_all
DELETE FROM `applications` WHERE `applications`.`id` IN (SELECT id FROM (SELECT `applications`.`id` FROM `applications` INNER JOIN `vacancies` ON `vacancies`.`id` = `applications`.`vacancy_id` WHERE `vacancies`.`status` = 'draft') __active_record_temp)