ActiveRecord:在特定日期创建没有孩子的父母的范围

时间:2016-04-19 20:06:56

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 activerecord

我希望在Rails 4中以ActiveRecord和Postgres作为数据库的一对多关系的特定日期创建 no 记录的所有父记录。

迁移:

class CreateParents < ActiveRecord::Migration
  def change
    enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')

    create_table :parents, id: :uuid, default: 'gen_random_uuid()' do |t|
      t.string :name
      t.timestamps null: false
    end
end

class CreateChilds < ActiveRecord::Migration
  def change
    create_table :childs, id: false do |t|
      t.uuid :parent_id, null: false
      t.date :created_at, null: false
      t.string :name
    end

    add_foreign_key :childs, :parents
    add_index :childs, [:parent_id, :created_at], :unique => true
  end
end

型号:

class Parent < ActiveRecord::Base
  has_many :childs
end

class Child < ActiveRecord::Base
  belongs_to :parent
end

现在我希望所有父母在特定日期都没有孩子,并且有一个范围:

class Parent < ActiveRecord::Base
  has_many :childs

  def self.with_no_childs_created_at(date)
    ...
  end
end

任何人都可以帮助我吗?我真的很生气。我在.includes.references.where.not.joins等方面做过很多尝试但是我没有得到它。

更新1

一个建议的解决方案看起来像这样:

def self.with_no_stats_created_at(date)
  joins(:childs).where.not(childs: {created_at: date})
end

但这仅在父母已经创建了过去的孩子时才有效。 SQL应该证明问题:

SELECT "parents".*
FROM "parents"
INNER JOIN "childs" ON "childs"."parent_id" = "parents"."id"
WHERE ("childs"."created_at" != $1)  [["created_at", "2016-04-19"]]

更新2

这解决了问题(由@Ilya建议):

def self.with_no_childs_created_at(date)
  preload(:childs).select {|p| p.childs.all? {|c| c.created_at != date }}
end

2 个答案:

答案 0 :(得分:1)

您可以预加载子项以避免N+1查询并像处理数组一样处理它:

def self.with_no_childs_created_at(date)
  preload(:childs).select {|p| p.childs.all? {|c| c.created_at != date }}
end

答案 1 :(得分:0)

你可以完全在数据库中完成,大部分时间都是这样:

$(document).ready(function() {
    if(url.indexOf('/looms/browse/?filtering=1') > -1){
        $("body").addClass("filterison");
    }
});