pasosdeJesus/msip

View on GitHub
doc/ejemplo-con-vistas-automaticas.md

Summary

Maintainability
Test Coverage
# Ejemplo de creación de tabla, modelo y controlador con vistas automáticas

Supongamos que se requiere una aplicación para manejar actividades.  
Usará msip con sus 2 roles por omisión (administradores y operadores), y ambos roles podrán administrar las actividades, es decir podrán ver, crear, editar y eliminar actividades.  Una actividad constará de un nombre, un valor y una fecha.  

Si aún no tienes una aplicación que use Msip, experimenta primero con [Iniciar un sistema de información usando Msip](https://gitlab.com/pasosdeJesus/msip/wiki/Iniciar-un-sistema-de-informaci%C3%B3n-usando-Msip).

Como la aplicación se dirige a usuarios de Colombia todo debe verse en español (incluyendo URLs), los nombres de las actividades deben compararse en español, los valores monetarios con localización de Colombia (e.g 1.000,4) y las fechas también deben estar en el formato de Colombia (e.g 10/Ene/2010).

# 1. Genera parcialmente migración, modelo y controlador

En una aplicación que ya use msip (ver [Iniciar un sistema de información usando Msip](iniciar-si-usando-msip)), puedes generar una migración parcial (para crear la tabla `actividad`), el modelo (`app/models/actividad.rb`) y el controlador (`app/controllers/actividades_controller.rb`) con:
```sh
$ DISABLE_SPRING=1 bin/rails g msip:modelo actividad actividades
```
Note que se requiere la forma singular del modelo (i.e `actividad`) y la plural (i.e `actividades`), pues la tabla y el modelo usarán la forma singular, mientras que el controlador y las vistas usarán la forma plural.

Tras generar archivos, completa la aplicación siguiendo las instrucciones que el generador da y que detallamos a continuación.

# 2. Modifica la migración generada

Por ejemplo, como una actividad consta de un nombre, valor y fecha, la migración quedaría así:
```rb
class CreateActividad < ActiveRecord::Migration[5.2]
  def change
    create_table :actividad do |t|
      t.text :nombre, limit: 254, null: false, collation: 'es_co_utf_8'
      t.date :fecha
      t.decimal :valor
      t.timestamp :created_at
      t.timestamp :updated_at
    end
  end
end
```

Ejecútala con
```sh
$ bin/rails db:migrate
```

En este momento podrías probar que se crea efectivamente la tabla y una inserción y eliminación de un dato con:
```sh
$ bin/rails dbconsole
...
\dt actividad
INSERT INTO actividad (nombre, fecha, valor, created_at, updated_at) VALUES ('Correr', '2019-12-5', '1000', '2019-12-5', '2019-12-5');
SELECT * from actividad;
DELETE FROM actividad WHERE nombre='Correr';
```

# 3. Establece el control de acceso

Modifica `app/models/ability.rb` agregando el control de acceso y su descripción (agrega `include CanCan::Ability`).  Suponiendo que le quisieras dar acceso para administrar las actividades a los roles `ROLADMIN` y `ROLOPERADOR` tendrías que:
1. Agregar `can :manage, ::Actividad` en los casos de `Ability::ROLADMIN` y `Ability::ROLOPERADOR` (o `ROLANALI`) de la función `initialize`.
2. Modificar `ROLES_CA` para agregar la descripción de este acceso para los roles indicados (si no ha cambiado los ROLES por omisión de `msip`, serán 1 para `ROLADMIN` y 5 para `ROLOPERADOR`), por ejemplo:
```rb
ROLES_CA = [
      "Administrar actividades. " +
      "Crear copias de respaldo cifradas. " +
      "Administrar usuarios. " +
      "Administrar tablas básicas. ", #1
      "", #2
      "", #3
      "", #4
      "Administrar actividades. ",  #5
      "" #6
    ]
```

# 4. Indica la inflección plural en español

Agrega manualmente la inflección no regular (respecto al inglés) en `config/initializers/inflections.rb` al estilo:
```rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular 'actividad', 'actividades'
end
```

Puedes probar que está operando la inflección que agregaste con:
```sh
$ bin/rails console
...
'actividad'.pluralize
```

# 5. Suministra nombres en español para los campos

Agrega el nombre del modelo y sus campos en español en `config/locales/es.yml`, por ejemplo, si no tenías otras cadenas, este archivo quedaría:
```yml
es:
  activerecord:
    attributes:
      "actividad":
        Actividad: Actividad
        Actividades: Actividades
        nombre: Nombre de la actividad
        fecha_localizada: Fecha de la actividad
        valor_localizado: Costo
```

# 6. Edita el modelo generado

En `app/models/actividad.rb` indica que la fecha y el valor serán localizados, que el nombre es requerido y que cuando se presente una actividad (por ejemplo en listados) debe presentarse su identificación, un guión y el nombre.

```rb
# encoding: UTF-8

class Actividad < ActiveRecord::Base
  include Msip::Modelo
  include Msip::Localizacion

  campofecha_localizado :fecha
  flotante_localizado   :valor

  validates :nombre, presence: true

  def presenta_nombre
    "#{id} - #{nombre}"
  end
end
```

Podrías probar la definición del modelo, insertando y eliminado un elemento con:

```sh
$ bin/rails console
...
Actividad.connection
a=Actividad.create!(nombre: 'Correr', valor: 1000, fecha: '2019-12-5', created_at: '2019-12-5', updated_at: '2019-12-5')
a.destroy
```


# 7. Edita el controlador generado

En `app/controllers/actividades_controller.rb` completa:
1. Los campos por mostrar en las vistas `index` (listado de actividades), `show` (resumen de una actividad) y `form` (formulario) en las funciones `atributos_index`, `atributos_show` y `atributos_form` respectivamente --como en este caso serán iguales (excepto que `id` no será editable en el formulario)-- basta especificar `atributos_index`
2. El criterio de ordenamiento para el listado de actividades (por omisión es `id` pero para este caso queremos por `nombre`)
3. El género de la palabra `actividad` (para que el botón "Nuevo" en el listado de actividades sea más bien "Nueva")

Quedará:
```rb
# encoding: UTF-8

class ActividadesController < Msip::ModelosController
  helper ::ApplicationHelper

  before_action :set_actividad,
    only: [:show, :edit, :update, :destroy]
  load_and_authorize_resource  class: ::Actividad

  def clase
    "::Actividad"
  end

  def atributos_index
    [
      :id,
      :nombre,
      :fecha_localizada,
      :valor_localizado
    ]
  end

  def index_reordenar(registros)
    return registros.reorder(:nombre)
  end

  def new_modelo_path(o)
    return new_actividad_path()
  end

  def genclase
    return 'F'
  end

  private

  def set_actividad
    @registro = @actividad = ::Actividad.find(
      ::Actividad.connection.quote_string(params[:id]).to_i
    )
  end

  # No confiar parametros a Internet, sólo permitir lista blanca
  def actividad_params
    params.require(:actividad).permit(*atributos_form)
  end

end
```

# 8. Agrega una ruta para las vistas automáticas

Editando `config/routes.rb`  agrega antes de la declaración de la ruta raiz `root`:
```rb
resources :actividades, path_names: { new: 'nueva', edit: 'edita' }
```

# 9. Agrega una entrada en el menú de la aplicación

Editando `app/views/layouts/application.html.erb` dentro de la sección de `menu_group`:
```erb
    <% if can? :read, ::Actividad %>
      <%= menu_item "Actividades", main_app.actividades_path %>
    <% end %>
```

# 9. Lanza la aplicación

Ejecuta
```sh
$ bin/rails s
```
navegus a http://localhost:3000/  ingresa al menú Actividades que presentará el listado paginado, con un botón "Nueva" para crear nuevas actividades y por cada actividad botones para editarla o eliminarla.