Última actualización
Última actualización
No abreviar nombres de variables, clases, métodos, etc. Priorizar que algo sea fácil de leer y que se pueda entender rápidamente lo que hace o qué representa, sin importar si queda un nombre más largo de lo que a un@ le gustaría.
Las variables de ambiente deberían ser definidas como métodos en un módulo para agruparlas y para que sea más fácil hacer mock de ellas. ()
Encapsular lógica de negocios en Jobs, sin importar si no es reutilizable, para limitar el tamaño de los controllers.
En API usar siempre memoization. En app usar set_model
explícito en el método de la acción. Nunca usar before_action
.
Preferir Shrine por sobre ActiveStorage para manejo de imágenes.
Serializer: Solo métodos para estructurar data que se ve a necesitar en una API
Decorador: Cosas que tienen html o especifico para consumo de vista por parte de Rails
Presenter: Lógica/condicionales para usar en vistas. En general se debería preferir Vue por sobre presenters.
Usamos PowerAPI para crear APIs
Cada controller debería manejar un solo recurso.
Todo lo que es API para uso interno (formularios, scroll infinito, etc) se usa PowerAPI en modo internal
Solo cuando la aplicación va a ser consumida de manera independiente a la web (app mobile) se usa las API exposed, teniendo tanto API interna como exposed si es necesario.
Se usa serialize_resource
para pasar variables de Rails a Vue :prop="<%= serialize_resource(@resource, @options) %>"
Para generar endpoints nuevos preferir usar el generador de PowerAPI (bin/rails generate power_api:controller my_resource
Preferir usar BaseController a la hora de agregar cosas como Pundit en vez de editar cada controller.
Serializers - No sacar el root. El formato de respuesta debería ser consistente en todos los serializers
Usar objetos decorados en serializer
Preferir respond_with
a render json:
Evitar agregar valores traducidos o formateados en la respuesta de una API. Idealmente los valores siempre se mandan sin formatear (fechas, números, moneda).
Valores para vistas deberían ir en serializer y/o decorador, métodos de datos deberían ir modelo.
Por definir: estructura REST de rutas - uso de verbos en url (https://platanus.slack.com/archives/C021F62E15G/p1651518650410749)
Para manejar callbacks después de un evento en un modelo usamos dos maneras:
Callbacks en el modelo cuando se editan atributos de la misma tabla
PowerTypes - Observers para ejecutar side-effects (mandar correos, crear otro recurso en otra tabla, etc)
Evitar side-effects en AASM (mandar emails, modificar otros modelos), usar Observers para eso.
Si se están usando estados de AASM, siempre usar sus eventos para cambiar de un estado a otro. No cambiar de estado con Resource.update
usar keys de locale en errores activemodel
En observers todo lo que depende de un recurso externo se ejecuta en perform_later
No tener lógica directo en el DSL de active admin. Usar jobs o servicios.
Si se usan componentes de Vue, se pueden llamar a los endpoint de AA directamente con .json
usando query params de Ransack si es necesario
A veces se necesita hacer una vista custom para ActiveAdmin, ya sea por un member_action
o algo como un form custom. Si la vista requiere mucho html, se puede usar un .erb
, pero si está más cargado al ruby, preferir usar un .arb
, qué nos permite usar la misma sintáxis que se usan en ActiveAdmin. Considerar también que es posible utilizar componentes Vue en estos templates de ActiveAdmin.
Preferir dos queries simples versus una query muy complicada.
pluck en vez de map para obtener atributos de un modelo
Preferir siempre métodos de ActiveRecord para las relaciones por sobre consultas con where o raw SQL. En otras palabras, no usar SQL “a mano”
En colecciones de ActiveRecord, preferir métodos de ActiveRecord sobre métodos de Ruby/Enumerable, para delegar el cálculo o búsqueda a la base de datos y no traer toda la colección a memoria innecesariamente. Una excepción puede ser cuando los elementos ya se cargaron previamente en memoria.
Usar transactions para grupos de acciones.
Los scopes siempre deberían ser chainables.
Preferir definir scopes en vez de definir queries en controllers.
Mientras menos nesteado el html, mejor. No agregar divs wrappers para agregar una sola clase a menos que sea 100% necesario.
Seguir guía de estilos de Vue a la hora de ponerle nombre a los componentes.
Si es que se hace inmanejable la cantidad de componentes, lo más probable es que la aplicación en si sea lo suficientemente grande como para dividir en engines, en cuyo caso los componentes deberían ir en sus carpetas de engine respectivas.
Usar href
en vez de @click
cuando la única acción que se quiere realizar es cambiar de página.
Usar variables multilinea en vez desactivar regla de eslint
Preferir librerías que no muten sus valores, por ejemplo date-fns en vez de moment.
Preferir sintaxis que ayude al tree-shaking, para bajar el tamaño del bundle.
Las promesas deberían estar con catch y mostrar feedback al usuario.
Estructuras repetidas deberían ser extraidas a componentes o ser usadas con v-for (sobre todo si se están usando métodos en vez de valores computed)
Preferir computed por sobre métodos (cuando son valores para el template)
Si hay CSS custom en <style>
usar scoped
para limitar su efecto al resto de la aplicación.
Inline SVGs:
Íconos SVG no deberían tener atributo fill
o deberían tener fill="currentColor"
para que tomen el color del texto.
https://github.com/jamesmartin/inline_svg (con inline_svg_tag
) cuando el svg se vaya a usar en un template de rails directamente.
En otro casos usar img con el SVG directamente en el src.
Evitar anidar elementos interactivos (<button>
dentro de )
<button>
siempre debería tener un type
<!-- ❌ --><form> <button @click="cancel">Cancelar</button> <button @click="submit">Enviar</button></form><!-- ✅ --><form @submit="submit"> <button @click="cancel" type="button">Cancelar</button> <button type="submit">Enviar</button></form>Base mínima a la que queremos llegar de accesibilidadPor lo mínimo los formularios deberían ser navegables con el teclado (inputs y botones en vez de divs, todo dentro de un form, evento submit debería ser manejado para que funcione el enter)Cada input debería tener un label, ya sea dentro del tag o con un id/for. Si por diseño no se puede ver un label, usar la clase sr-only
para esconderlo.Evitar @click
en cosas que no sean links o botones. No usar divs.No usar outline-none en los elementos a menos que el focus se marque de otra manera (focus-visible
)Todos los formularios deben ser implementados en Vue con submit mediante API.Preferir Vue por sobre Rails (y presenters) cuando hayan condicionales o cosas dinámicas. Considerar casos de uso futuros a la hora de decidir.En lo posible la primera carga de una página nunca debería requerir esperar más requests para mostrar contenido. Usar el mismo serializer para el prop y el endpoint de la API (serialize_resource
)No usar tags self-closing en .erb
. Se usan en Vue por ser más simples y rápidas de usar, pero en HTML normal no son válidas y tienden a romper el template de manera misteriosa.<!-- ❌ --><super-component /><!-- ✅ --><super-component></super-component>Si en un test se necesita seleccionar un elemento, no agregar una clase, ref o cualquier otro atributo que ya tenga otro significado. Para esto se le puede agregar al elemento un data-testid="something"
si es un elemento único, o data-test
si no lo es**Por definir: **Qué hacer con variables globales que vienen desde Rails (ej, current user) y se necesitan en VueEn Vue 3, poner primero el <script>
, luego el <template>
y al final <style>
si es que hay
State Management (Pinia, Vuex)
El store debería estar normalizado (array de ids + objeto con ids identificando cada item)
Evitar usar getters que acepten parámetros. Si es necesario que un getter sea dinámico, los parámetros deberían ser atributos del mismo store.
Solo en Vuex: Mutaciones deberían ir en su propio archivo como constantes.
Las interfaces que definen cosas que vienen del backend deberían ir en la carpeta api/
, aun si definen cosas que no tienen un endpoint especifico o no tienen endpoint todavía. Por ejemplo si están haciendo un Form
pero este Form
tiene FormCategory
y FormField
, las tres irían en un mismo archivo api/form.ts
y se exportarían hacia los componentes desde ahí.
Las interfaces que definen cosas internas que solo se usan en en un mismo componente deberían ir dentro de <script setup>
. Si es algo que usan varios componentes, definir en la carpeta /types
, de preferencia como exports. En algunos casos puede ser preferible usar interfaces globales pero en general evitar para no causar confusiones del tipo “de donde salió este type”.
Extraer clases repetidas a componentes o iterar templates (con .each
o v-for
)
No cambiar tamaño base de fuente en body
Considerar estados (active, focus, hover) a la hora de agregar estilo a elementos interactivos
Usar paper_trail
Usar devise-two-factor
PR de ejemplo: https://github.com/platanus/ventures-nest/pull/322/files
Usar act-as-taggable-on
Tener todos los componentes en la misma carpeta. Fuente ()
Si un componente es global y básico (inputs, botones) usar prefijo base
. Ejemplos: base-input
, base-modal
.
Si es un componente que se usa una sola vez (headers, footers, etc) usar prefijo The
. Ejemplos: the-header
, the-contact-form
Componentes que solo se van a usar en otro componente, tienen de prefijo el nombre de ese componente. Ejemplo: the-header-nav-bar
.
Usar kebab-case
en vez de PascalCase
ya que usamos el DOM template en las vistas de Rails.
Usar puede ahorrar mucho tiempo si el proyecto tiene varios formularios con el mismo estilo.
Todos los iconos o si se necesita cambiar el color de un SVG que no es un icono, usar . La librería es necesaria para que los SVGs queden insertados directamente en el template en vez de quedar como imágenes enlazadas, y así puedan ser modificados con css.
Normalmente esto pasa cuando se quiere que todo un elemento sea clickable pero que además tenga acciones extras. La solución es separar las acciones secundarias de la acción principal:
Usamos en vez de Vuex.
para state management
para hacer requests a APIs + para manejar los estados de loading/success/error
para manejar fechas
para utilidades varias usando la Composition API.
Aparte de agregar los colores y fuente de la marca, tratar de no modificar ni extender mucho el theme
de tailwind. Ver si se puede obtener un resultado suficientemente parecido usando las clases ya existentes. Si se necesita un valor arbitrario que no está en estas clases, y este valor se usa en solo una parte, preferir agregarlo