@besukosan さん
itemを結合させることに囚われてましたが、よくよく考えると、シンプルに書けそうです。
Post.where.not(id: Item.where(reject: false).pluck(:post_id))
Post has_man Items
という関連において「Reject(却下)がfalseのItemを含まない、Post」を検索したいのですが試行錯誤の末自力で解決出来ずにおります。。
Post.includes(:items).where.not(items: {reject:false})
シンプルに以上のように実装すると、Reject:falseを含んだものも検索出来てしまいます。。
includesとwhere.notは相性が良くないのでしょうか。。
尚、今回は{rejection:true}とする検索は異なる結果となりますので想定しておりません。
妙案をご存知の方おられましたらお力を貸して頂けますと嬉しいです!
@besukosan さん
itemを結合させることに囚われてましたが、よくよく考えると、シンプルに書けそうです。
Post.where.not(id: Item.where(reject: false).pluck(:post_id))
@besukosan
Questioner@besukosan さん、こんにちは。
解決策ですが、下記コマンドで取得できるかと思われます。
Post.joins(:items)
.where.not(items: { reject: false })
# 必要あればdistinctもつける
Post.joins(:items)
.where.not(items: { reject: false })
.distinct
# ちなみにですが、to_sqlを最後につけるとどういったSQLが発行されるか確認することができます。
Post.joins(:items)
.where.not(items: { reject: false })
.to_sql
includesは使い方を間違うと予期せぬ挙動となるため、注意が必要です。
joins、includesなどrailsを使っていく上で避けては通れない知識になってきますので、この機会にぜひ学習されると良いかもしれません。
@besukosan
Questioner@besukosan さん
なるほど。「関連するItems全てがreject: trueのPostのみ抽出する」ってことですね・・・。
一応期待するデータが取得できる書き方考えたんですが、他に良い書き方あるかもしれません。
items = Item
.where(id: Item.group(:post_id, :reject).pluck(:id))
.group(:post_id)
.having('count(*) = 1')
Post.joins(:items)
.where(items: { id: items.pluck(:id), reject: true })
簡単に解説すると、最初のitems
で post_id
と reject
の組み合わせが一つだけのitemを取得します(この段階ではrejectはtrueかもしれないしfalseかもしれない)。
あとはそのitem idを指定して、かつ、rejectがtrueのものを検索しヒットしたitemのPostを取得する、という流れです。
思ったより長くなってしまいました・・・。
他にも良い方法あるかとは思いますが、一度試していただき期待通りのデータが取得されればうれしいです。
@besukosan
Questioner