无法将SQL查询转换为Arel

时间:2014-11-28 09:02:00

标签: ruby-on-rails database ruby-on-rails-3 arel

我有一个缩小特定类列表的搜索页面,我想要一个可以抓住两个不同条件的OR条件并将它们加在一起,例如,我有类

模型/ party.rb

class Party < ActiveRecord::Base

  has_many :invitations
end

模式/ invitation.rb

class Invitation < ActiveRecord::Base

   belongs_to :party
end

邀请具有状态属性,该属性将为&#34;拒绝&#34;,&#34;接受&#34;或&#34;未答复&#34;

我想要做的就是抓住所有没有邀请的政党,或任何拥有所有邀请的政党&#34;未得到答复&#34;。

我目前正在做

  scope :not_confirmed, lambda { find_by_sql( "SELECT * FROM `parties` INNER JOIN `invitations` ON `invitations`.`party_id` = `parties`.`id` WHERE (invitations.status = 'unanswered') OR (parties.id NOT IN (SELECT DISTINCT(party_id) FROM invitations))" ) }

有效,但由于它没有延迟加载,我无法将其添加到类似查询的方面。

我做了类似

的事情
no_invitations.or(no_one_has_answered)

但它不起作用。

我特别不明白在AREL上使用OR的概念,有人可以帮帮忙吗?

编辑:

对于一个非常丑陋但功能性的工作,直到我解决这个问题,这就是我所做的

party.rb

  scope :not_confirmed, lambda { joins(:invitations).where( "invitations.status NOT IN (?)", ["accepted", "declined" ] ) }
  scope :with_no_invitations, lambda { includes(:invitaions).where( :invitations => { :party_id => nil } ) }

search_controller.rb

@parties = Party.all_the_shared_queries
@parties = ( @parties.not_confirmed + @parties.with_no_invitations).uniq

2 个答案:

答案 0 :(得分:2)

查询:

  scope :not_confirmed, lambda { find_by_sql( "SELECT * FROM `parties` INNER JOIN `invitations` ON `invitations`.`party_id` = `parties`.`id` WHERE (invitations.status = 'unanswered') OR (parties.id NOT IN (SELECT DISTINCT(party_id) FROM invitations))" ) }

也可以使用布尔代数进行一些转换,转换为。但由于只有理论转换,您必须手动验证它。所以:

class Invitation < ActiveRecord::Base
   belongs_to :party

   scope :non_answered, -> { where(arel_table[:status].not_eq('unanswered')) }
end

class Party < ActiveRecord::Base
   has_many :invitations

   scope :not_confirmed, -> { not.join(:invitaions).merge(Invitation.non_answered)) }
end

请在此测试并发表评论。

答案 1 :(得分:1)

首先,从问题标签开始,我假设您使用的是Rails3(如果它是Rails4,有更简单的方法可以做到:)

根据您的要求(即抓住所有没有邀请的参与者,或任何拥有所有邀请的参与者&#34;未答复&#34;),这是一种方式这样做(使用范围:无人值守):

派对模特:

class Party < ActiveRecord::Base
  has_many :invitations
  scope :invitations_answered, -> { joins(:invitations).merge(Invitation.answered) }
  scope :unattended, -> { where(arel_table[:id].not_in invitations_answered.pluck(:id)) }
end

邀请模特:

class Invitation < ActiveRecord::Base
  belongs_to :party
  scope :answered, -> { where(status: ["decline", "accept"])}
end

在Rails 4中,您可以使用where.not并进一步简化它:

派对模特:

class Party < ActiveRecord::Base
  has_many :invitations
  scope :invitations_answered, -> { joins(:invitations).merge(Invitation.answered) }
  scope :unattended, -> { where.not(id: invitations_answered.pluck(:id)) }
end

邀请模特:

class Invitation < ActiveRecord::Base
  belongs_to :party
  scope :answered, -> { where.not(status: 'unanswered') }
end