Rails: ActsAsList – Herramienta para manipular posición de objetos en una lista
Publicado el 3 de abril de 2012La clase con esta necesidad específica debe tener una columna position
(posición) definida como Integer
en la tabla de base de datos mapeada.
Es bastante sencilla de usar, pueden agregar a su Gemfile
la gema:
gem 'acts_as_list'
Voy a mostrar un ejemplo bastante sencillo en Rails a efectos de explicar el concepto. Tenemos una aplicación Rails con dos modelos: Book y Bookshelf. Generamos los modelos correspondientes:
$ rails generate model Bookshelf name:string
$ rails generate model Book title:string author:string description:text position:integer bookshelf:references
Y mandamos a generar las tablas:
$ rake db:migrate
Editamos el código de app/models/bookshelf.rb para agregar el orden:
class Bookshelf < ActiveRecord::Base has_many :books, :order => 'position' end |
Y el libro:
class Book < ActiveRecord::Base belongs_to :book_shelf acts_as_list :scope => :bookshelf end |
Hecho esto ya estamos en condiciones de tener una Bookshelf con una colección de libros, y manipular el orden de los libros dentro de esta colección a través del índice “position”. Podemos probar el código en la consola de Rails con:
$ rails console
Empezamos por crear un bookshelf para guardar nuestros libros:
bookshelf = Bookshelf.new(:name => "My bookshelf") |
Hecho esto, creamos algunos libros asignándoles nuestro objeto bookshelf:
> book1 = Book.new(:title => "1984", :author => "George Orwell", :description => "Dystopian future", :bookshelf => bookshelf) > book2 = Book.new(:title => "A princess of Mars", :author => "Edgar Rice Burroughs", :description => "John Carter is in this book", :bookshelf => bookshelf) > book3 = Book.new(:title => "Ready Player One", :author => "Ernest Cline", :description => "Online virtual world / videogame", :bookshelf => bookshelf) > book4 = Book.new(:title => "Foundation", :author => "Isac Aasimov", :description => "Blow-your-mind-Sci-fi", :bookshelf => bookshelf) |
Ya armada la estructura y guardada podemos ver que los libros tienen su posición según fueron siendo guardados:
> bookshelf.books Book Load (0.3ms) SELECT "books".* FROM "books" WHERE "books"."bookshelf_id" = 1 ORDER BY position => [#<Book id: 1, title: "1984", author: "George Orwell", description: "Dystopian future", position: 1, bookshelf_id: 1, created_at: "2012-04-03 02:46:36", updated_at: "2012-04-03 02:46:36">, #<Book id: 2, title: "A princess of Mars", author: "Edgar Rice Burroughs", description: "John Carter is in this book", position: 2, bookshelf_id: 1, created_at: "2012-04-03 02:46:38", updated_at: "2012-04-03 02:46:38">, #<Book id: 3, title: "Ready Player One", author: "Ernest Cline", description: "Online virtual world / videogame", position: 3, bookshelf_id: 1, created_at: "2012-04-03 02:46:40", updated_at: "2012-04-03 02:46:40">, #<Book id: 4, title: "Foundation", author: "Isac Aasimov", description: "Blow-your-mind-Sci-fi", position: 4, bookshelf_id: 1, created_at: "2012-04-03 02:46:42", updated_at: "2012-04-03 02:46:42">] |
El cuarto libro por ejemplo, podemos moverlo a la primera posición, y tras recargar los objetos, vemos que automáticamente los demás libros sumarán una posición más:
> book4.position => 4 > book4.move_to_top #Mover a la primera posición (0.1ms) begin transaction SQL (0.3ms) UPDATE "books" SET position = (position + 1) WHERE ("books"."bookshelf_id" = 1 AND position < 4) (0.3ms) UPDATE "books" SET "position" = 1, "updated_at" = '2012-04-03 02:47:55.303110' WHERE "books"."id" = 4 (105.5ms) commit transaction => true > book4.position => 1 |
Podemos comprobar las posiciones de los demás libros:
book1.position => 2 > book2.position => 3 |
Y mover un libro al final de la lista:
> book2.move_to_bottom (0.1ms) begin transaction SQL (0.3ms) UPDATE "books" SET position = (position - 1) WHERE ("books"."bookshelf_id" = 1 AND position > 3) Book Load (0.3ms) SELECT "books".* FROM "books" WHERE ("books"."bookshelf_id" = 1 AND id != 2) ORDER BY position DESC LIMIT 1 (0.3ms) UPDATE "books" SET "position" = 4, "updated_at" = '2012-04-03 02:50:13.740681' WHERE "books"."id" = 2 (107.7ms) commit transaction => true > book2 = Book.find 2 Book Load (0.2ms) SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT 1 [["id", 2]] => #<Book id: 2, title: "A princess of Mars", author: "Edgar Rice Burroughs", description: "John Carter is in this book", position: 4, bookshelf_id: 1, created_at: "2012-04-03 02:46:38", updated_at: "2012-04-03 02:50:13"> > book2.position => 4 |
Y la posición final de todos los libros quedó:
> bookshelf.books Book Load (0.3ms) SELECT "books".* FROM "books" WHERE "books"."bookshelf_id" = 1 ORDER BY position => [#<Book id: 4, title: "Foundation", author: "Isac Aasimov", description: "Blow-your-mind-Sci-fi", position: 1, bookshelf_id: 1, created_at: "2012-04-03 02:46:42", updated_at: "2012-04-03 02:47:55">, #<Book id: 1, title: "1984", author: "George Orwell", description: "Dystopian future", position: 2, bookshelf_id: 1, created_at: "2012-04-03 02:46:36", updated_at: "2012-04-03 02:46:36">, #<Book id: 3, title: "Ready Player One", author: "Ernest Cline", description: "Online virtual world / videogame", position: 3, bookshelf_id: 1, created_at: "2012-04-03 02:46:40", updated_at: "2012-04-03 02:46:40">, #<Book id: 2, title: "A princess of Mars", author: "Edgar Rice Burroughs", description: "John Carter is in this book", position: 4, bookshelf_id: 1, created_at: "2012-04-03 02:46:38", updated_at: "2012-04-03 02:50:13">] |
Una herramienta bastante útil con otros métodos como move_higher
, move_lower
, y más que pueden leer en el código fuente. Si quieren leer más al respecto visiten acts_as_list.
No hay comentarios en este post
Feed de comentariosDejar un comentario
<pre lang="L"> código </pre>
Siendo L un lenguaje compatible GeSHI. Más info.