Acciones de Controlador y Pruebas en Ruby on Rails
Resumen
¿Cómo crear una nueva acción de controlador en Rails?
En el desarrollo de aplicaciones Rails, la creación de acciones de controlador que interactúan con Service Objects es clave para mantener organizada la lógica del negocio. Aquí explicaremos cómo crear una nueva acción de controlador para gestionar los estados de una tarea, garantizando además su correcto funcionamiento mediante pruebas.
¿Cómo agregar una nueva acción al controlador?
Localizar y editar el controlador de tareas:
Abre el archivo del controlador de tareas y busca un lugar adecuado para adicionar la nueva acción.
Definir la acción y su estructura:
Agrega la función def trigger dentro del controlador. Esta acción recibirá un parámetro que permitirá actualizar el estado de una tarea específica.
deftrigger# Aquí se instancia el servicio para modificar el estado de la tareaend
Modificar el before_action:
Es necesario incluir la acción trigger en el before_action para configurar el evento justo antes de ejecutar esta acción.
Dentro de config/routes.rb, agrega la nueva ruta usando el verbo HTTP patch, que es apropiado para editar recursos existentes.
resources :tasksdo member do patch :triggerendend
Verificar las rutas creadas:
Utiliza la consola de comandos con rails routes para confirmar que la ruta se ha integrado correctamente.
¿Cómo escribir pruebas para garantizar el funcionamiento?
Preparar el entorno de prueba:
Accede al archivo de pruebas de petición en la carpeta spec/requests.
Definir la prueba:
Añade un nuevo bloque describe y dentro de este, la prueba para la acción trigger. Esto asegura que el estado de la tarea se actualice correctamente.
describe "PATCH /tasks/:id/trigger"do it "updates the task state"do task = create(:task) patch trigger_task_path(task),params:{event:'start'} task.reload
expect(task.state).to eq('inprocess')endend
¿Cómo manejar el acceso con CanCan?
Asegurar autorizaciones:
Confirma que el usuario autentificado es el propietario de la tarea, dado que CanCan evalúa los permisos basados en la propiedad de la tarea.
# En el contexto de definición del propietario de la tarealet(:user){ create(:user)}let(:task){ create(:task,owner: user)}
Ejecutar las pruebas:
Corre las pruebas con rspec para verificar que el sistema reconozca las autorizaciones y la funcionalidad esté intacta.
Crear una nueva acción de controlador que interactúa con un Service Object optimiza el manejo de estados en una aplicación Rails. Además, el establecimiento de pruebas contundentes garantiza la fiabilidad de su implementación. Considera extender las pruebas a casos negativos para asegurar una robustez aún mayor. ¿Listo para ello? ¡Adelante, marco a marco, tu proyecto crecerá!
Creo que la definición de la clase Tasks::TriggerEvent no es la más adecuada, porque en la llamada al método call en el action trigger tienes que crear una instancia vacía para poder llamar al método.
Mi propuesta es tener un constructor que reciba task y event, y después llamar solamente al método call.
Y ya cuando se invoque lo podemos hacer de la siguiente manera:
Tasks::TriggerEvent.new(task, event).call
Para el desafió, podemos generar un test para el escenario donde se utiliza el evento 'finish' cuando nos encontramos en el estado 'pending' de la siguiente manera:
require 'rails_helper'RSpec.describe"Tasks",type::request dolet(:user){create:user }before(:each){login_as(user,scope::user)} describe "GET /tasks"do it "works! (now write some real specs)"doget tasks_path
# expect(response).tohave_http_status(200)expect(response.body).toinclude("Lista de Tareas") end
end
describe "PATCH /tasks/:id/trigger"dolet(:participants_count){4}let(:event){'start'}let(:otherEvent){'finish'}subject(:task)dobuild(:task_with_participants,owner: user,participants_count: participants_count) end
it 'update the state'do task.save patch trigger_task_path(task),params:{event: event }expect(task.reload.status).to eq 'in_process' end
it 'cannot update the state'do task.save patch trigger_task_path(task),params:{event: otherEvent }expect(response).tohave_http_status(:no_content)expect(task.reload.status).to eq 'pending' end
end
end
Si les aparece el error:
NoMethodError:
undefined method `trigger_task' for #<RSpec::ExampleGroups::Tasks::PATCHTasksIdTrigger "update the state" (./spec/requests/tasks_spec.rb:32)>