Comment combiner deux étendues avec OU

J'ai un flux de tags et un flux d'amis. Je veux combiner ces deux et construire l'ultime "tout" flux.

Pour le flux d'un ami:

class Post < ActiveRecord::Base
  scope :friendfeed, lambda{|x| followed_by}

  def self.followed_by(user)
    where("user_id IN (?) OR user_id = ?", user.watched_ids, user.id)
  end
end

Pour le tag feed:

class Post < ActiveRecord::Base
  scope :tagfeed, lambda{|x| infatuated_with}

  def self.infatuated_with(user)
    joins(:attachments).where("attachments.tag_id IN (?)", user.tags).select("DISTINCT pages.*")
  end
end

Et je voudrais appeler quelque chose comme ça de la part du contrôleur (j'utilise Kaminari gem pour la pagination):

@tag_feed = Post.tagfeed(current_user).page(params[:page]).per(21)
@friend_feed = Post.friendfeed(current_user).page(params[:page]).per(21)

Maintenant, je veux avoir un flux universel, mais je suis perdu. Les portées sont destinées à rétrécir, mais dans ce cas, j'essaye de faire une opération OR. Faire des trucs comme

@mother_of_all_feed = @tag_feed + @friend_feed

serait redondant, et je ne serais pas en mesure de contrôler le nombre de messages apparaissant sur une seule page. Comment puis-je faire cela? Merci!

En passant, pour les tags, j'ai une association mise en place comme ceci:

class Post < ActiveRecord::Base
  has_many :attachments
  has_many :tags, :through => :attachments
end

class Tag < ActiveRecord::Base
  has_many :attachments
  has_many :posts, :through => :attachments
end

class Attachment < ActiveRecord::Base
  belongs_to :tag
  belongs_to :post
end
0

2 Réponses

Il y a une demande d'extraction de rails pour cette fonctionnalité ( https://github.com/rails/rails/pull/ 9052 ), mais en attendant, quelqu'un a créé un correctif de singe que vous pouvez inclure dans vos initialiseurs, ce qui vous permettra d'utiliser ou d'étendre les clauses where dans une requête tout en vous donnant un ActiveRecord :: Relation :

https://gist.github.com/j-mcnally/250eaaceef234dd8971b

Avec cela, vous seriez en mesure de OU vos étendues comme celle-ci

Post.tagfeed(current_user).or.friendfeed(current_user)

ou écrire une nouvelle portée

scope :mother_of_all_feed, lambda{|user| tagfeed(user).or.friendfeed(user)}
0
ajouté
Des critiques constructives seraient appréciées de quiconque dénigrerait cela. Il résout le problème, et sans générer de requêtes imbriquées.
ajouté l'auteur keithepley, source
OU sera ajouté à Rails 5.0: github.com/rails/rails/pull/16052
ajouté l'auteur denis.peplin, source
Oui, le OR a été ajouté à ActiveRecord :: Relation # ou dans Rails 5 - nithinbekal.com/posts/rails-5-features
ajouté l'auteur leviathan, source

Répondre à ma propre question. Je pense que j'ai trouvé un moyen.

where("pages.id IN (?) OR pages.id IN (?)",
  Page.where(
      "user_id IN (?) OR user_id = ?",
      user.watched_ids, user.id
  ),
  Page
    .joins(:attachments)
    .where("attachments.tag_id IN (?)", user.tags)
    .select("DISTINCT pages.*")
)

Il semble fonctionner jusqu'à présent, j'espère que c'est ça!

0
ajouté
Pas satisfait, mais je faisais juste du prototypage donc c'est OK. Je vais jeter un coup d'oeil à Squeel. Merci!
ajouté l'auteur Vlad, source
Êtes-vous satisfait de sa performance? On dirait que vous obtenez 4-5 requêtes ici. Il semble que vous ayez deux options: écrire une requête SQL brute ou utiliser mon outil favori. Il permet d'exécuter OR et prend en charge la fonctionnalité in qui conduit à une requête SQL imbriquée. Jetez un coup d'oeil: github.com/ernie/squeel . J'ai essayé de "faire de la publicité" peu de fois, comme ici: stackoverflow.com/a/10551561/1322562 , mais seulement qu
ajouté l'auteur jdoe, source