2014-01-12 3 views
1

У меня есть модель Post.Дайте каждому экземпляру экземпляра пользовательскую позицию заказа

Я хотел бы указать на основе «постобрания» их заказ.

Я предполагаю, что атрибут position:integer - хорошее начало.

Это пример того, что будет оказана с Post.order(position: :asc):

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

Но как процедура обновления будет сделано тогда? Или любые другие, лучшие идеи?

+1

'Post.order (ID:: asc) '? –

+0

Прошу прощения, что они только закажут их по их идентификатору, мне нужно более точно контролировать позицию. –

+1

Вы можете использовать драгоценный камень [ActsAsList] (https://github.com/swanandp/acts_as_list) для обработки процедуры обновления, не нужно изобретать колесо;) – Stefan

ответ

3

Я предполагаю, что у вас уже есть атрибут position для всех ваших записей. Вы должны, кстати, убедитесь, что он не может быть нулевым:

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

Скажет, у вас есть Post, который в настоящее время является девятой должностью и должен быть пятой пост.

Прежде всего, вам необходимо временно удалить сообщение из списка позиций. Все сообщения с позиции 10 и выше необходимости убавления одно:

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) 
+0

Отлично, спасибо. Два вопроса: 1) Где и как вы устанавливаете значение 'position_was'? 2) Почему разрыв между 5 и 9 в вашем примере? –

+0

Разрыв только для иллюстративных целей, без особого значения. В этом примере я изменяю порядок существующего сообщения. 'position_was' содержит предыдущее значение значения позиции. Rails делает это для вас: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html. Обратите внимание, что, проверяя, был ли установлен параметр 'position_was', я определяю, следует ли сначала удалить сообщение из списка позиций. – fivedigit

+0

И «.transaction', и' _was »были для меня новичком, спасибо за просветление (и тщательный ответ). –

Смежные вопросы