为每个Post实例提供自定义订单位置

时间:2014-01-12 08:55:26

标签: ruby-on-rails ruby

我有一个Post型号。

我想在“逐个帖子”的基础上指定他们的订单。

我认为position:integer属性是一个好的开始。

这是使用Post.order(position: :asc)呈现的示例:

id: 3, position: 1
id: 2, position: 2
id: 8, position: 3
...

但是如何更新程序呢?还是其他任何更好的想法?

1 个答案:

答案 0 :(得分:3)

我假设您已经为所有记录设置了position属性。顺便说一句,你应该确保它不能为零:

change_column :posts, :position, :integer, null: false

假设您有一个Post,目前是第9个帖子,需要成为第5个帖子。

首先,您需要暂时从位置列表中“删除”帖子。位置10和更高位置的所有帖子都需要减1:

Post.where('position > ?', 9).update_all('position = position - 1')

然后你需要把它放回到位置列表中。这是通过从当前第五个位置开始递增所有位置来完成的:

Post.where('position >= ?', 5).update_all('position = position + 1')

整个过程涉及两个数据库查询,并且您不会将大量的ActiveRecord对象加载到内存中。

你可以这样做before_update回调:

class Post
  before_create :update_positions
  before_update :update_positions, if: :position_changed?

  def update_positions
    if position_was
      Post.where('position > ?', position_was).update_all('position = position - 1')
    end
    Post.where('position >= ?' position).update_all('position = position + 1')
  end
end

显而易见的最后一部分,无论何时展示帖子,都按位置订购:

Post.all.order(:position)