Hola a todos los que visitan estos documentos…
Pues bien aqui me tienen con otro ejercicio en ruby on rails ahora tratando de resolver un pequeño problema…
Pasemos al problema
Bien lo que quiero hacer aqui es una relacion n:n de dos tablas…
Veamos el problema
Tengo una tabla con alumnos y a cada alumno le quiero asignar uno o mas grupos y en la misma proporcion uno grupos puede estar asignado a uno o mas alumnos….
Pues manos a la obra
Primero debemos crear nuestra base de datos, en este caso yo la llame escuela
fvasquez@inf:~$ sudo mysqladmin create escuela
Y vamos a crear la tabla de usuarios en este caso solamente vamos a crear el indice y un campo que sera para el nombre del alumno
CREATE TABLE `usuarios` (
`id` int(11) NOT NULL auto_increment,
`nombre` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Tambien vamos a crear la tabla de grupos y le vamos a ingresar directamente unos valores, como estos valores quiza no se alteren no necesitaremos tener un metodo de captura para esta tabla asi que desde este momento le asignaremos valores a la tabla.
CREATE TABLE `grupos` (
`id` int(11) NOT NULL auto_increment,
`nombre` varchar(30) NOT NULL,
`valor` varchar(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
INSERT INTO `grupos` (`id`, `nombre`, `valor`) VALUES
(1, ‘primero’, ’01’),
(2, ‘segundo’, ’02’),
(3, ‘tercero’, ’03’),
(4, ‘cuarto’, ’04’),
(5, ‘Quinto’, ’05’),
(6, ‘Sexto’, ’06’);
Y aqui viene lo bueno……….
Ahora debemos cumplir la relacion n:n a nivel de base de datos para lo cual construimos una tercera tabla la cual nos servira de enlace entre las dos anteriores, y la cual contendra los indices de usuarios y grupos
CREATE TABLE `grupos_usuarios` (
`usuario_id` int(11) NOT NULL,
`grupo_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Bien ya tenemos nuestras tablas, ahora si a trabajar en el entorno de ruby on rails
fvasquez@inf:~$ rails escuela
Con esto tenemos construida la estructura para nuestro proyecto
Ahora a editar
Editamos el archivo config/database.yml y lo dejamos como se muestra a continuacion
fvasquez@inf:~/escuela$ nano config/database.yml
development:
adapter: mysql
database: escuela
username: root
password:
socket: /var/run/mysqld/mysqld.sock
# Warning: The database defined as ‘test’ will be erased and
# re-generated from your development database when you run ‘rake’.
# Do not set this db to the same as development or production.
test:
adapter: mysql
database: escuela
username: root
password:
socket: /var/run/mysqld/mysqld.sock
production:
adapter: mysql
database: escuela
username: root
password:
socket: /var/run/mysqld/mysqld.sock
Ahora tenemos el enlace a nuestra base de datos, con esto ya podemos ayudarnos de scaffold para construir el CRUD de nuestras tablas…
Vamos a crear el templete para la tabla de usuarios, scaffold nos creara el controlador, el modelo, las vistas y otras cosas mas que necesitamos…
fvasquez@inf:~/escuela$ ruby script/generate scaffold Usuario
Vamos a prender nuestro servidor mongrel y vemos en el navegador que tenemos….
fvasquez@inf:~/escuela$ ruby script/server mongrel -d
Y nos vamos al navegador
localhost:3000/usuarios/
Y tenemos un programa funcional donde podemos agregar, eliminar, editar, mostrar, listar el contenido de la tabla usuario.
Vamos con los grupos …
El objetivo es mostrar al mismo tiempo un campo de la tabla grupos desplegado en check_box’s y de esa manera hacer mas facil al usuario la seleccion..
Ahora vamos a trabajar con la tabla de grupos como la tabla grupos ya tiene valores que le asignamos en el momento de la creacion de la tabla, y estos valores van constantes entonces para esta tabla solo vamos a crear su modelo…
fvasquez@inf:~/escuela$ ruby script/generate model Grupo
Ya tenemos los modelos de las tablas usuarios y grupos, ahora podemos indicar la relacion n:n a nivel programacion
Editamos los modelos y los dejamos como se muestra a continuacion
fvasquez@inf:~/escuela$ nano /app/models/usuario.rb
class Usuario < ActiveRecord::Base
has_and_belongs_to_many :grupos
end
fvasquez@inf:~/escuela$ nano /app/models/grupo.rb
class Grupo < ActiveRecord::Base
has_and_belongs_to_many :usuarios
end
Con esto le queremos decir que un usuario tiene y pertenece a muchos grupos y un grupo tiene y pernetenece a muchos usuarios, con esto cumplimos la relacion n:n
Ahora vamos a modificar la vista de nuestro usuario para integrarle los campos de la tabla de grupos y poder asignar valores en ambas tablas en una misma forma
fvasquez@inf:~/escuela$ nano app/views/usuarios/_form.rhtml
y lo dejamos como se muestra a continuacion
<%= error_messages_for ‘usuario’ %>
Nombre
<%= text_field ‘usuario’, ‘nombre’ %>
<% for g in Grupo.find(:all) %>
<%= g.nombre %>
<% end %>
Lo que hicimos aqui es un ciclo asignandole al objeto g todos los elementos del objeto Grupo y crear un chek_box_tag se ayude del arreglo grupo_ids para almacenar los elementos que se seleccionen tomando el valor del campo id del objeto g, y va a relacionarlos en la tabla grupos_usuarios
El metodo create y el update de nuestro proyecto utilizan el mismo principio asi que vamos a ver como funcionan ambos…
Al parecer el metodo update cuando eliminamos elementos de la lista nos mantiene los mismos y no se actualizan como deberia asi que vamos a nuestro controlador a modificar el metodo edit.
def update
params[:usuario][:grupo_ids] ||= []
@usuario = Usuario.find(params[:id])
if @usuario.update_attributes(params[:usuario])
flash[:notice] = ‘Usuario was successfully updated.’
redirect_to :action => ‘show’, :id => @usuario
else
render :action => ‘edit’
end
end
Si nos damos cuenta solo ingresamos esta linea
params[:usuario][:grupo_ids] ||= []
Esto quiere decir que el parametro grupo.ids del objeto Usuario.update se va a evaluar contra un arreglo vacio a traves de un OR y si el valor de la izquierda es nulo (.nil) etonces se nos devolvera el valor de la derecha que en este caso es un arreglo vacio..
Bien solo falta mostrar la lista de todos los usuarios y por cada uno de ellos que grupos que tienen asignados…
A editar nuevamente y dejamos el archivo como se muestra a continuacion
fvasquez@inf:~/escuela$ nano app/views/usuarios/list.rhtml
Listing usuarios
<%= column.human_name %> | ||
---|---|---|
<%=h usuario.send(column.name) %> | <%=h g.nombre %> | |
<%= link_to ‘Show’, :action => ‘show’, :id => usuario %> | <%= link_to ‘Edit’, :action => ‘edit’, :id => usuario %> | <%= link_to ‘Destroy’, { :action => ‘destroy’, :id => usuario }, :confirm => ‘Are you sure?’, :method => :post %> |
_ |
<%= link_to ‘Previous page’, { :page => @usuario_pages.current.previous } if @usuario_pages.current.previous %>
<%= link_to ‘Next page’, { :page => @usuario_pages.current.next } if @usuario_pages.current.next %>
<%= link_to ‘New usuario’, :action => ‘new’ %>
Lo que agregamos fue esto que es un ciclo que esta dentro de cada usuario para mostrar el campo nombre de la tabla grupos basandose en la relacion n:n que se hizo con la tabla grupos_usuarios
<%for g in usuario.grupos%>
- <%=h g.nombre %>
<%end%>
Bueno aqui les dejo esto…
Cualquier sugerencia o critica es bienvenida
Faustino Vasquez Limon
Universidad Xochicalco Campus Tijuana
Linux User: “Agrega Espacio a Tu Disco Duro Quitando Windows”