且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Ruby on Rails的最适合在过滤器值数组搜索?

更新时间:2023-11-01 20:41:52

您使用user_ids的想法是好的。如果该查询返回一个空数组,那么你检查,以确保该user_ids是你期望的人?

对于code,你需要考虑的可枚举#地图 #flat_map 。它们是内置红宝石的方法来完成你想要的#each循环做什么。您code可能会降低到这样的:

  user_ids = user.followings.flat_map {|以下| following.following_id}
user_ids.uniq!
user_ids - = [user.id,user.following_ids] .flatten
Post.where(USER_ID:user_ids).order(ID:DESC).limit(21)

请注意:由于created_at应遵循ID创建订单,我会寻找基于ID,而不是created_at,因为它应该有一个指标考虑

I have a specific example, but the general question is: whats the optimal way to retrieve records when you have an array of filter values to match?

Say I have User and Post records where User has_many :posts

and I have a Relationship model that looks like this:

class Relationship < ActiveRecord::Base
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end

I want to write a function that returns chronologically ordered posts from your followings' following - that is, all the posts from users that the users you follow are following, excluding duplicates and posts from anyone you follow.

My solution is to first compile an array of all the users of interest:

users = []
@user.following.each do |f|
  f.following.each do |ff|
    users << ff
  end
end

# dedupe
users = users.uniq

#remove self and following
users.delete(@user)
@user.following.each do |f|
  users.delete(f)
end

then compile their posts and order them:

posts = []
users.each do |u|
  posts += u.posts
end
posts.sort_by!{|x| x[:created_at]}.reverse!

I think there's a better way to do this with Active Record functions, but I can't figure out how to make them work with an array. For instance, if I compile an array of User id values instead of the full models, and try to run this code to get the post array:

posts = Post.where(
  user_id: user_ids
).order('created_at DESC').limit(21)

it returns an empty array. Is there a better way to search with an array of filter values than my current solution?

Update: additional modal code:

class Post < ActiveRecord::Base
  belongs_to :user
  ...

User.rb

class User < ActiveRecord::Base
  has_many :photos
  has_many :active_relationships, class_name:  "Relationship",
                              foreign_key: "follower_id",
                              dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                               foreign_key: "followed_id",
                               dependent:   :destroy
  has_many :following, through: :active_relationships, source: :followed
  has_many :followers, through: :passive_relationships, source: :follower
  ...

Your idea of using user_ids is a good one. If that query returned an empty array, then did you check to make sure that the user_ids were the ones that you expected?

As for the code, you need to look into Enumerable#map and #flat_map. They are built-in ruby methods to accomplish what you're trying to do with the #each loops. Your code might reduce to something like:

user_ids = user.followings.flat_map { |following| following.following_id }
user_ids.uniq!
user_ids -= [user.id, user.following_ids].flatten
Post.where(user_id: user_ids).order(id: :desc).limit(21)

Note: Since created_at should follow id creation order, I would consider searching based on id rather than created_at since it should have an index.