3

I have a Rails engine that defines a class method top(count) on a model of choice. What this method does is grab count IDs from a sorted set (ZSET) in Redis. The idea is that each item of this model has a score, and this method is to return the "best" records. The method essentially looks like this:

def self.top(count = 1)
  ids = redis.zrevrange(self.score_set, 0, count - 1)
  items = self.find ids

  if count == 1
    return items.first
  else
    return items.sort { |x, y| ids.index(x.id) <=> ids.index(y.id) }
  end
end

As you can see, I currently sort the records after the fact because databases (or the adapters) tend not to maintain order when finding by multiple IDs. For instance, Model.where('ID IN (?)', ids) will sort by ascending IDs rather than the order of the passed IDs.

Sorting the items returns an Array, but I'd like this method to return an ActiveRecord::Relation instead so that my users can chain it with other ActiveRecord query methods. Is there a way I can use the built-in ActiveRecord query methods to maintain order from my array of IDs? Or alternatively, is there a way to construct an ActiveRecord::Relation from an array of records?

4

1 に答える 1

4

それは実際にあなたが使用している基礎となるデータベースに依存します。Railsにはこれを行うための良い方法があるとは思いません。

私はあなたと同じことをしているアプリケーションを持っています。IDをRedisZSETに保存し、その順序で取得する必要があります。MySqlを使用しているので、フィールド関数を利用できます。

Model.where('id in (?)', ids).order("field(id, #{order})")

orderPS:変数がサニタイズされていることを確認してください!

于 2012-06-28T00:34:15.310 に答える