Este documento describe los pasos para configurar las relaciones entre modelos y tablas en una aplicación Ruby on Rails. Inicialmente, se definen las irregularidades de nombres en singular y plural. Luego, se generan los modelos y tablas usando scaffolding para diferentes entidades como carreras, profesores, salones, etc. Finalmente, se agregan validaciones a los modelos y se establecen las relaciones entre las tablas para habilitar funcionalidades como listar alumnos por materia.
1. 1
Curso Ruby On Rails
Antes de iniciar a trabajar con Rails debemos indicarle la pronunciación de singular y plural del
nombrado de nuestras tablas (todo en minusculas):
Por ejemplo:
alumnos -> alumnos
Imaginemos que no hacemos esta declaración y manejaremos la tabla direcciones, entonces Rails
tomara como singular direccione, esto no ocasiona problemas alguno, pero es un poco incomodo
trabajar con este nombre de variables que son poco descriptivas y difíciles de recordar.
Para el caso de alumnos no habría problemas si no se declara ya que el singular sera alumno, pero
es mejor mantener esta practica para evitar problemas.
Agregamos el nombre de todos lo modelos a utilizar.
# config/initializers/infections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'alumno', 'alumnos'
inflect.irregular 'carrera', 'carreras'
inflect.irregular 'materia', 'materias'
inflect.irregular 'direcion', 'direciones'
inflect.irregular 'profesor', 'profesores'
inflect.irregular 'salon', 'salones'
inflect.irregular 'periodo', 'periodos'
end
2. 2
Esta sera la base de datos con la que trabajaremos, la cual crearemos con la ayuda de
Scaffold.
Para realizar este ejercicio es necesario que la base de datos
NO TENGA ninguna tabla.
Para limpiar tu Base de datos
1. Elimina todas las tablas
2. Ejecuta las siguientes instrucciones en la terminal (para eliminar archivos creados
por scaffold)
rails d scaffold carreras
rails d scaffold profesores
rails d scaffold salones
rails d scaffold periodos
rails d scaffold materias
rails d scaffold alumno_materias
rails d scaffold alumnos
3. 3
Creación de sacffold
Para generar los modelos y las tablas de base de datos, vamos a ejecutar las siguientes instrucciones, con
la consola de ruby (Ejecuta lina por linea)
rails g scaffold carreras carrera:string nomenclatura:string
rake db:migrate
rails g scaffold profesores carrera:references profesor:string
rake db:migrate
rails g scaffold salones salon:string
rake db:migrate
rails g scaffold periodos periodo:string
rake db:migrate
rails g scaffold materias periodo:references carrera:references profesor:references salon:references
materia:string creditos:integer creditos_min:integer semestre:integer
rake db:migrate
rails g scaffold alumnos carrera:references nombre:string apellido_p:string apellido_m:string
no_control:string semestre:integer
rake db:migrate
rails g model alumno_materias alumno:references materia:references semestre:integer calificacion:float
rake db:migrate
--- En linux:
bin/rake db:migrate RAILS_ENV=development
--- En Windows
rake db:migrate RAILS_ENV=development
Esto nos generara los archivos necesarios para poder realizar CRUD para cada scaffold creado, ahora se
deberán de modificar los formularios (_form.html.erb), se reemplazaran los f.text_field por
f.collection_select, para que en lugar de que muestre un input para introducir la carrear, nos aparezca
una lista desplegable con las carreras para seleccionar:
# Ejemplos de reemplazo en el archivo _form.html.erb de profesores
<%= f.text_field :carrera_id %>
<%= f.collection_select(:carrera_id, Profesor.all, :id, :profesor) %>
# Se reemplazara para los datos que pertenecen a llaves foraneas.
Y realizamos lo mismo con el resto de los formularios.
4. 4
También eliminamos los satos de linea <br> (Para que no quede tan separado, cuando apliquemos
skeleton.css mas adelante), esto en todo el formulario.
<div class="field">
<%= f.label :profesor %><br>
<%= f.text_field :profesor %>
</div>
5. 5
Agregando validaciones
Las solución anterior funciona, pero es hora de agregar algunas validaciones para antes de guardar la
información.
Validaciones a considerar:
● EL nombre debe tener mínimo 3 caracteres y un máximo de 50
● El apellido paterno es requerido
● El no_control
■ debe ser único
■ Solo se admiten numero (aun que el campo en bd es string)
■ Se compone de 8 números
Para lo cual nos vamos a la carpeta de modelos, y abrimos el archivo de alumno.rb
Y agregamos las validaciones (de paso, las relaciones y un método privado):
class Alumno < ActiveRecord::Base
# Relación con la tabla carreras y materias
belongs_to :carrera
has_many :Materias, :class_name => "AlumnoMateria", :foreign_key => "alumno_id"
# Validaciones
validates :nombre, length: { in: 3..50 , message: " debe tener minimo 3 caracteres"}
validates :apellido_p, presence: { message: "Escribe el apellido paterno" }
validates :no_control, uniqueness: {message: "ya se encuentra registrado"}
validates :no_control, length: { is: 8, message: "Debe tener 8 caracteres" } #17590063
validates :no_control, numericality: {message: "Solo se admiten numeros"}
# Metodo privado, para recuperar el nombre completo del alumno
def nombre_completo
self.nombre + " " + self.apellido_p + " " + self.apellido_m
end
def materias_cursando
self.Materias.where("alumno_materias.semestre = #{self.semestre}")
end
def materias_x_cursar
# La siguiente consulta puede generar las siguientes consultas
# SELECT `materias`.* FROM `materias` WHERE (`materias`.`id` NOT IN (2, 3))
# SELECT `materias`.* FROM `materias` WHERE (`materias`.`id` != 2)
Materia.where.not( id: self.Materias.map { |m| m.materia_id } )
end
End
6. 6
Las validaciones se ejecutaran tanto para los
nuevos registros como para las
actualizaciones.
Una vez ejecutado y modificado lo anterior, debemos agregar datos al sistema en este orden.
http://localhost:3000/periodos
http://localhost:3000/carreras
http://localhost:3000/profesores
http://localhost:3000/salones
http://localhost:3000/materias
http://localhost:3000/alumnos
7. 7
Agregando algo de maquillaje.
Para agregar estilo a la aplicación visual usaremos el fremework http://getskeleton.com/. para lo cual
requerimos de dos archivos normalize.css y skeleton.css
En el archivo: `config/initializers/assets.rb` debemos declarar los archivos css, que
nuestra aplicación utilizara, por seguridad, debemos hacer esto para todos los archivos css y js.
# `config/initializers/assets.rb`
Rails.application.config.assets.version = '1.0'
Rails.application.config.assets.precompile += %w( normalize.css )
Rails.application.config.assets.precompile += %w( skeleton.css )
Después de modificar el archivo, reiniciamos el servidor de rails para que los cambios se vean
reflejados.
Modificamos
<!DOCTYPE html>
<html>
<head>
<title>Curso Rails</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<!-- Se incluyen los archivos css de skeleton -->
<%= stylesheet_link_tag 'normalize', media: 'all', 'data-turbolinks-track' => true %>
<%= stylesheet_link_tag 'skeleton', media: 'all', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!-- container, esta declarada en skeleton.css -->
<div class="container">
<%= yield %>
</div>
</body>
</html>
9. 9
Relaciones entre Modelos
Como los modelos se crearon mediante scaffold y haciendo referencia a otras tablas,
Rails genera las relaciones a nivel código, por ejemplo para el modelo profesores:
class Profesor < ActiveRecord::Base
belongs_to :carrera
end
Para la dirección: http://localhost:3000/profesores
En la columna carrera nos muestra algo
“raro”, esto es la representación de un
objeto. Para que nos muestre la carrera
debemos modificar:
<%= profesor.carrera%>
Por:
<%= profesor.carrera.carrera %>
profesor. .carrera .carrera
Objeto que se esta
iterando
Nombre de la
relación en
profesores
Nombre de la
columna. En la
tabla carreras
<tbody>
<% @profesores.each do |profesor| %>
<tr>
<td><%= profesor.carrera.carrera %></td>
<td><%= profesor.profesor %></td>
<td><%= link_to 'Show', profesor %></td>
<td><%= link_to 'Edit', edit_profesor_path(profesor) %></td>
<td><%= link_to 'Destroy', profesor, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
Este cambio se deberá realizar en todos los archivos index.html.erb y show.html.erb
10. 10
Un poco mas allá de las relaciones
Las ultimas dos relaciones, son para recuperar la lista de todos los alumnos, que están
cursando una materia.
La penultima relación es usada para lograr una relación directa, con la tabla, materias ya
alumnos, esta relación sirve de puente.
La ultima relación, source: :alumno indica el origen de datos de la relación, en este caso
los son de la tabla de alumnos.
class Materia < ActiveRecord::Base
belongs_to :periodo
belongs_to :carrera
belongs_to :profesor
belongs_to :salon
# Relaciones adicionales
has_many :AlumnoMaterias, :foreign_key => "materia_id"
has_many :Alumnos, through: :AlumnoMaterias, source: :alumno
end
11. 11
Alumno Materias
Para que funcione este modulo es necesario hacer una modificación en routes.rb
resources :alumnos do
resources :alumno_materias
end
Con esto accedemos desde la url: http://localhost:3000/alumnos/1/alumno_materias/new
Y para ver las materias que esta cursando el alumnos, sera mediante la url:
http://localhost:3000/alumnos/1 modificando el archivo show.html.erb
Del controlador alumno_materias_controller.rb, solo usaremos los métodos: :new, :create
y :destroy.
En la clase, tenemos dos métodos, que antes de ejecutar un metodo, se inicializar la variable
@alumno.
class AlumnoMateriasController < ApplicationController
before_action :set_alumno, only: [:new, :create, :destroy,:update]
before_action :set_alumno_materia, only: [:update, :destroy]
private
# params[:alumno_id] :alumno_id, siempre llegara desde la URL
def set_alumno
@alumno = Alumno.find(params[:alumno_id])
end
# este metodo solo se ejecuta para :update, :destroy
def set_alumno_materia
@alumno_materia = AlumnoMateria.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def alumno_materia_params
params.require(:alumno_materia).permit(:materia_id)
end
end