Module: Sortifiable::InstanceMethods

Defined in:
lib/sortifiable.rb

Overview

All the methods available to a record that has had acts_as_list specified. Each method works by assuming the object to be the item in the list, so chapter.move_lower would move that chapter lower in the list of all chapters. Likewise, chapter.first? would return true if that chapter is the first in the list of all chapters.

Instance Method Summary collapse

Instance Method Details

#add_to_listObject

Add the item to the end of the list



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/sortifiable.rb', line 104

def add_to_list
  if in_list?
    move_to_bottom
  else
    list_class.transaction do
      ids = lock_list!
      last_position = ids.size
      if persisted?
        update_position last_position + 1
      else
        set_position last_position + 1
      end
    end
  end
end

#current_positionObject

Returns the current position



121
122
123
# File 'lib/sortifiable.rb', line 121

def current_position
  send(position_column).to_i
end

#decrement_positionObject

Decrease the position of this item without adjusting the rest of the list.



126
127
128
# File 'lib/sortifiable.rb', line 126

def decrement_position
  in_list? && update_position(current_position - 1)
end

#first?Boolean Also known as: top?

Return true if this object is the first in the list.

Returns:

  • (Boolean)


131
132
133
# File 'lib/sortifiable.rb', line 131

def first?
  in_list? && current_position == 1
end

#first_itemObject Also known as: top_item

Returns the first item in the list



137
138
139
# File 'lib/sortifiable.rb', line 137

def first_item
  list_scope.first
end

#higher_itemObject Also known as: previous_item

Return the next higher item in the list.



143
144
145
# File 'lib/sortifiable.rb', line 143

def higher_item
  item_at_offset(-1)
end

#higher_itemsObject

Return items lower than this item or an empty array if it is the last item



149
150
151
# File 'lib/sortifiable.rb', line 149

def higher_items
  list_scope.where(["#{quoted_position_column} < ?", current_position]).to_a
end

#in_list?Boolean

Test if this record is in a list

Returns:

  • (Boolean)


154
155
156
# File 'lib/sortifiable.rb', line 154

def in_list?
  !new_record? && !send(position_column).nil?
end

#increment_positionObject

Increase the position of this item without adjusting the rest of the list.



164
165
166
# File 'lib/sortifiable.rb', line 164

def increment_position
  in_list? && update_position(current_position + 1)
end

#insert_at(position = 1) ⇒ Object

Insert the item at the given position (defaults to the top position of 1).



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/sortifiable.rb', line 169

def insert_at(position = 1)
  list_class.transaction do
    ids = lock_list!
    position = [[1, position].max, ids.size].min

    if persisted?
      current_position = ids.index(id) + 1

      sql = <<-SQL
        #{quoted_position_column} = CASE
        WHEN #{quoted_position_column} = #{current_position} THEN #{position}
        WHEN #{quoted_position_column} > #{current_position}
        AND #{quoted_position_column} <= #{position} THEN #{quoted_position_column} - 1
        WHEN #{quoted_position_column} < #{current_position}
        AND #{quoted_position_column} >= #{position} THEN #{quoted_position_column} + 1
        ELSE #{quoted_position_column}
        END
      SQL

      list_scope.update_all(sql)
      update_position(position)
    else
      save!

      sql = <<-SQL
        #{quoted_position_column} = CASE
        WHEN #{quoted_position_column} >= #{position} THEN #{quoted_position_column} + 1
        ELSE #{quoted_position_column}
        END
      SQL

      list_scope.update_all(sql)
      update_position(position)
    end
  end
end

#item_at_offset(offset) ⇒ Object

Return the item at the offset specified from the current position



207
208
209
# File 'lib/sortifiable.rb', line 207

def item_at_offset(offset)
  in_list? ? offset_scope(offset).first : nil
end

#last?Boolean Also known as: bottom?

Return true if this object is the last in the list.

Returns:

  • (Boolean)


212
213
214
# File 'lib/sortifiable.rb', line 212

def last?
  in_list? && current_position == last_position
end

#last_itemObject Also known as: bottom_item

Returns the bottom item



218
219
220
# File 'lib/sortifiable.rb', line 218

def last_item
  list_scope.last
end

#last_positionObject Also known as: bottom_position

Returns the bottom position in the list.



224
225
226
# File 'lib/sortifiable.rb', line 224

def last_position
  last_item.try(:current_position) || 0
end

#lower_itemObject Also known as: next_item

Return the next lower item in the list.



230
231
232
# File 'lib/sortifiable.rb', line 230

def lower_item
  item_at_offset(1)
end

#lower_itemsObject

Return items lower than this item or an empty array if it is the last item



236
237
238
# File 'lib/sortifiable.rb', line 236

def lower_items
  list_scope.where(["#{quoted_position_column} > ?", current_position]).to_a
end

#move_higherObject Also known as: move_up

Swap positions with the next higher item, if one exists.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/sortifiable.rb', line 241

def move_higher
  if in_list?
    list_class.transaction do
      ids = lock_list!
      current_position = ids.index(id) + 1

      if current_position > 1
        sql = <<-SQL
          #{quoted_position_column} = CASE
          WHEN #{quoted_position_column} = #{current_position} - 1 THEN #{current_position}
          WHEN #{quoted_position_column} = #{current_position} THEN #{current_position} - 1
          ELSE #{quoted_position_column}
          END
        SQL

        set_position current_position - 1
        list_scope.update_all(sql) > 0
      else
        true
      end
    end
  else
    false
  end
end

#move_lowerObject Also known as: move_down

Swap positions with the next lower item, if one exists.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/sortifiable.rb', line 269

def move_lower
  if in_list?
    list_class.transaction do
      ids = lock_list!
      current_position, last_position = ids.index(id) + 1, ids.size

      if current_position < last_position
        sql = <<-SQL
          #{quoted_position_column} = CASE
          WHEN #{quoted_position_column} = #{current_position} + 1 THEN #{current_position}
          WHEN #{quoted_position_column} = #{current_position} THEN #{current_position} + 1
          ELSE #{quoted_position_column}
          END
        SQL

        set_position current_position + 1
        list_scope.update_all(sql) > 0
      else
        true
      end
    end
  else
    false
  end
end

#move_to_bottomObject

Move to the bottom of the list. If the item is already in the list, the items below it have their position adjusted accordingly.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/sortifiable.rb', line 298

def move_to_bottom
  if in_list?
    list_class.transaction do
      ids = lock_list!
      current_position, last_position = ids.index(id) + 1, ids.size

      if current_position < last_position
        sql = <<-SQL
          #{quoted_position_column} = CASE
          WHEN #{quoted_position_column} = #{current_position} THEN #{last_position}
          WHEN #{quoted_position_column} > #{current_position} THEN #{quoted_position_column} - 1
          ELSE #{quoted_position_column}
          END
        SQL

        set_position last_position
        list_scope.update_all(sql) > 0
      else
        true
      end
    end
  else
    false
  end
end

#move_to_topObject

Move to the top of the list. If the item is already in the list, the items above it have their position adjusted accordingly.



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/sortifiable.rb', line 326

def move_to_top
  if in_list?
    list_class.transaction do
      ids = lock_list!
      current_position = ids.index(id) + 1

      if current_position > 1
        sql = <<-SQL
          #{quoted_position_column} = CASE
          WHEN #{quoted_position_column} = #{current_position} THEN 1
          WHEN #{quoted_position_column} < #{current_position} THEN #{quoted_position_column} + 1
          ELSE #{quoted_position_column}
          END
        SQL

        set_position 1
        list_scope.update_all(sql) > 0
      else
        true
      end
    end
  else
    false
  end
end

#remove_from_listObject

Removes the item from the list.



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/sortifiable.rb', line 353

def remove_from_list
  if in_list?
    list_class.transaction do
      ids = lock_list!
      current_position = ids.index(id) + 1

      sql = <<-SQL
        #{quoted_position_column} = CASE
        WHEN #{quoted_position_column} = #{current_position} THEN NULL
        WHEN #{quoted_position_column} > #{current_position} THEN #{quoted_position_column} - 1
        ELSE #{quoted_position_column}
        END
      SQL

      set_position nil
      list_scope.update_all(sql) > 0
    end
  else
    false
  end
end

#will_leave_list?Boolean

Test if this record is in a scoped list but will leave the scoped list when saved

Returns:

  • (Boolean)


159
160
161
# File 'lib/sortifiable.rb', line 159

def will_leave_list?
  in_list? && scope_parts.any? { |scope_part| send("#{scope_part}_changed?") }
end