Hay varias opciones para mantener a raya los logs en desarrollo. La primera es configurar en
config/environments/development.rb
el Logger
de Rails para que rote los ficheros:
1
|
|
Con estos parametros nuestro fichero de log rotaría al alcanzar 2 megas y no almacenaríamos ficheros antiguos (así es como me gusta a mi, pero en la documentación de la clase Logger podéis ver que hay más opciones de rotación.
Otra posibilidad es utilizar un servicio de loggin del operativo, por ejemplo usar syslog
y configurarlo como prefiramos.
1
|
|
Esta opción es más flexible ya que nos permite tener fuera de la aplicación la configuración (así cada desarrollador puede ponerla a su gusto). De todos modos, al igual que en el primer caso, esto nos obliga a acordarnos de configurar el logger cada vez que creamos una nueva aplicación y eso es “demasiado esfuerzo”. Mi solución favorita es no tocar nada en las aplicaciones Rails y utilizar un servicio de rotación de logs como se hace en producción: lograte en Linux y newsyslog en Mac OSX, configurado de tal modo que se roten todos los logs de las aplicaciones que estoy desarrollando.
Con lograte, añadimos un fichero en la carpeta /etc/logrotate.d/
tal que así:
1 2 3 4 5 6 7 |
|
y si usamos newsyslog lo añadimos a la carpeta /etc/newsyslog.d/
:
1 2 |
|
Easy peasy lemon squeezy ;)
]]>Clara se une a la familia Trabe para realizar unas prácticas de tres meses tras los que esperamos que se quede con nosotros todo el tiempo que quiera. De momento viene a aprender y a echar una mano al lado Java de Trabe.
A Lucas ya habíamos tenido el privilegio de tenerlo entre nosotros allá por el 2008, antes de que se fuese a vivir una aventura vital por Sudamérica y el Sudeste Asiático durante casi dos años. Ahora ha vuelto para demostrar que segundas partes sí pueden ser buenas y nos echará una mano con nuestros desarrollos Ruby on Rails y JavaScript.
Os damos las gracias a los dos por apuntaros a la aventura Trábica. Esperamos que lo paséis bien y aprendamos y crezcamos todos juntos.
Y como sois dos, toca poner dos gifs animados de Jake! :D
Como siempre en Trabe, 2014 ha sido un año intenso que nos ha traido algún hasta luego y un par de bienvenidas: una y dos. Por lo demás, hemos seguido participando en charlas, eventos y todo lo que habéis ido viendo en el blog
Para acabar el año, como es tradición, lo hemos montado muy bien ;)
Feliz 2015 a todos!!
]]>Lo que nos interesa de tmux es la posibilidad de iniciar una sesión de shell y desconectarnos (detach) de ella para volver a recuperarla más adelante. Por ejemplo: abrir una sesión SSH, lanzar un proceso largo dentro de tmux y cerrar la conexión para, más adelante, volver a conectarnos y recuperar la sesión. Es habitual que las conexiones SSH tengan timeouts y si no estamos atentos, se cierren matando nuestros procesos y alterando nuestra presión arterial. ¡tmux al rescate!.
Un ejemplo de sesión de trabajo usando tmux podría ser así:
david@localhost $ ssh david@remotehost
david@remotehost $ tmux new-session -s big_work
david@remotehost (tmux) $ ./launch_big_work.sh
Starting BIG work. ETA 4h
# detach pulsando en el teclado [C-b] d
[detached]
david@remotehost $ exit
logout
Connection to remotehost closed.
david@localhost $
# 4 horas después...
david@localhost $ ssh david@remotehost
david@remotehost $ tmux attach -t big_work
Starting BIG work. ETA 4h.
Work done. Yay!
david@remotehost (tmux) $ exit
david@remotehost $ exit
logout
Connection to remotehost closed.
david@localhost $
No hay nada especial que hacer, solo tener instalado tmux en la máquina remota y fijarse en que la combinación de teclas
para hacer detach es Ctrl+b
y después d
, que parece lo mismo que Ctrl+b+d
pero no lo es :D
Es super práctico y no cuesta nada recordarlo. Merece la pena :)
Para ir un paso más allá, podéis tener en vuestras máquinas remotas unos alias para facilitar la gestión de sesiones. En mi caso me gusta usar estos (que son los que también uso en mi máquina local):
tmn='tmux new-session -s'
tma='tmux -2 attach -t'
tmk='tmux kill-session -t'
tml='tmux list-sessions'
Espero que os sea de ayuda. Probadlo. Os gustará :)
]]>Esperamos que os parezcan unas charlas interesantes. Nos vemos en la FIC.
]]>La inscripción a las jornadas es gratuita y ya está abierta. Si estáis interesados, inscribíos, las plazas son limitadas.
Nos vemos en las jornadas :)
]]>En este caso se trata de Cecilia (Ceci para los amigos), que ha estado haciendo su Trabajo de Fin de Grado en Trabe y, tras recibir una estupenda matrícula de honor, se va a quedar con nosotros para echarnos una mano. En su proyecto estuvo trabajando con Redis y Sidekiq; y la experiencia que ha adquirido nos va a venir muy bien para proyectos que estamos desarrollando actualmente.
Esperamos que Ceci siga aprendiendo mucho con nosotros; y estamos seguros de que ella nos enseñará muchas cosas y que juntos aprenderemos muchas más.
Ceci, que disfrutes de tu aventura Trábica. Welcome! :)
En este caso, se trataría de realizar un aplicación móvil (nombre provisional: “Pizarreitor” xD), que cubriría una necesidad de Trabe: subir fotos a nuestras tarjetas de Trello. Desde hace más de un año estamos usando Trello como herramienta de gestión de proyectos y una de las funcionalidades que ofrece la herramienta es adjuntar archivos a las tarjetas. Otra cosa que hacemos es pintar diagramas en el encerado o en papel, y para adjuntarlos como documentación solemos sacar una foto con el móvil, enviarnos la imágen por correo y adjuntarla al Trello. Esto también se puede hacer con la propia app móvil de Trello pero es necesario bucear por varios menús hasta encontrar la opción adecuada. Lo que nos gustaría es tener una aplicación que nos permita sacar una foto y utilizando el API de Trello adjuntarla a una tarjeta de un proyecto de manera sencilla.
La aplicación podría ser desarrollada para iOS (iOS8 y Swift) y/o Android, y podrían incluirse otras funcionalidades como procesado de fotos (por ejemplo limpiar y realzar la foto de la pizarra), por lo tanto el tamaño del proyecto se podría ajustar.
Si alguien está interesado, sólo tiene que enviar un correo a contacto@trabesoluciones.com.
¿Quién se anima?
]]>Si juntamos ambas cosas, surge la posibilidad de que uno o varios estudiantes puedan realizar un proyecto relacionado con Thymeleaf en Trabe a partir de Septiembre.
La idea que manejo es crear una versión de Thymeleaf para Ruby (de ahí el original nombre de Thymeleaf.rb). Esta versión se basará en las funcionalidades de Thymeleaf 2.1 pero no copiará la implementación. Lo importante en este proyecto es crear la infraestructura necesaria (incluído el soporte de testing y benchmarking) y crear una implementación lo más sencilla posible sin preocuparnos del rendimiento. La acompañaríamos de otra librería (thymeleaf-rails) que nos permita usar thymeleaf.rb como motor de plantillas en aplicaciones Rails.
¿Qué nos aporta esto? Pues creo que varias cosas, entre otras: dar visibilidad al proyecto Thymeleaf en la comunidad RoR o tener un motor de plantillas común para los stacks Java y RoR que usamos en Trabe.
Creo que puede ser un proyecto interesante con el que se puede aprender mucho, así que si alguien está interesado, sólo tiene que enviar un correo a contacto@trabesoluciones.com.
¿Quién se anima?
]]>Querido Fuco, han sido tres años llenos de risas en los que hemos aprendido un montón de cosas gracias a ti (y no sólo me refiero a la jovial tradición medieval de la brea y la pluma xD). Has ayudado a Trabe a ser mejor empresa tanto a nivel tecnológico como humano y por eso, en nombre de todos los Trábicos, quiero darte las gracias.
Te echamos mucho de menos, pero sabemos que vas a ser muy feliz y vas a disfrutar mucho de tu aventura. Trabe es tu casa y su puerta siempre está abierta para ti. Vete enfriando las cervezas que pronto iremos por Berlín a que nos enseñes las maravillas de tu nuevo hogar :)
]]>Los ganadores del reto: Francisco y Juán Carlos, se llevaron cada uno una bonita Nexus 7 Wifi de 16Gb (que no están los tiempos para ir tirando gigas por ahí :D). Gracias por participar. Esperamos que os animéis a liberar vuestro proyecto, Rubik, cuando lo hayáis pulido :)
]]>Rails
Java
Tanto con Rails como con Java, utilizamos HTML5, CSS3 y Javascript para la capa vista (también usamos Coffescript, SASS y LESS). Además solemos usar Twitter Bootstrap como base.
Valoraremos positivamente el conocimiento de otras tecnologías y herramientas que usamos (Git, Thymeleaf, AngularJS, Backbone, etc.) y la capacidad para desarrollar aplicaciones móviles Android o iOs.
Un puesto de trabajo con un sueldo competitivo, seguro médico, horario flexible, jornada de verano, posibilidad de teletrabajar, oficina en el centro (zona plaza de Galicia), equipamiento de calidad, ambiente distendido y mucho más.
Si crees que este trabajo es para ti, envianos un correo a rrhh@trabesoluciones.com y cuentanos quién eres, a qué te dedicas, qué sabes hacer, por qué te gustaría trabajar con nosotros y por qué crees que eres la persona que buscamos. Nos encanta la sinceridad y siempre valoramos tanto el conocimiento como el interés. Si puedes, no olvides enseñarnos algo que hayas hecho (proyectos en los que hayas participado, código Open Source, etc.).
Esperamos vuestros correos. Prometemos responder a todos :)
]]>Adaptarlo a Bash y a otros operativos queda como ejercicio para el lector ;)
]]>Solemos desarrollar aplicaciones web desde cero, así que nuestro candidato perfecto tendría esta pinta:
No te asustes. Nadie en Trabe tiene este perfil y sabemos que es muy dificil encontrar a alguien que lo cumpla. Buscamos gente que venga a sumar y mejore nuestro equipo.
Lo que ofrecemos es un contrato fijo con un sueldo competitivo, seguro médico, horario flexible, jornada de verano, posibilidad de teletrabajar, oficina en el centro, ambiente distendido y mucho más.
Si crees que este es un trabajo para ti, no nos envíes un CV estándar (tu foto, tus datos y todo eso), envíanos un correo a rrhh@trabesoluciones.com y cuéntanos por qué te interesa el trabajo, qué experiencia tienes, qué te gusta, qué te disgusta y por qué. Si puedes enseñarnos algo que hayas hecho, mucho mejor. Puede ser un proyecto que has realizado en otra empresa y que sea público, un proyecto personal o una librería open-source. Dinos qué cumples del candidato ideal y no te tires de la moto: sabemos que nadie va a encajar al 100%.
Si tienes alguna duda pon un comentario en el post o envianos un correo. Gracias.
]]>No hace falta que seáis unas máquinas (aunque estaría bien xD). La idea es que paséis el verano en nuestra oficina (en el centro de Coruña) trabajando con nosotros en proyectos reales, aprendiendo todo lo que hace falta para desarrollar una aplicación web. El horario y la remuneración lo negociaremos en función de vuestra experiencia previa (aunque no es necesaria, esto son unas prácticas) y disponibilidad. Tenemos bastante flexibilidad.
Si os interesa, no nos enviéis un CV estándar. Preferimos que nos contéis en un correo dirigido a rrhh@trabesoluciones.com qué estáis estudiando y si ya tenéis alguna experiencia profesional (ya hemos dicho que no es necesaria ¿verdad?), qué os interesa, qué os disgusta, qué queréis aprender, etc.
No os tiréis de la moto. Sed sinceros. Valoraremos tanto el conocimiento como el interés. Si podéis, enseñadnos algo que hayáis hecho antes en otras prácticas/empleo, un proyecto personal o alguna aportación a proyectos open source. Os dará puntos.
Esperamos vuestros correos.
]]>But don’t despair.
First of all we have to get a basic idea of how Devise authenticates your resources. This explanation might be a bit rough so I’m going to use the following diagram to ease the explanation (kudos to asischao for his help).
The output of this process is an authenticated resource. Or not.
So, from this list of steps it seems that we have the following spots to work on:
Lets assume that our resource is a PORO called User
1 2 3 |
|
Devise requires some functionallity that we usually have for free when using ActiveRecord
resources. As this is not the case we have to do some plumbing: include some ActiveModel
modules and extend the class using Devise::Models
.
1 2 3 4 5 6 7 |
|
At this point we are ready to configure Devise.
1 2 3 |
|
To understand a bit better what we are doing here take a look at the following Devise modules:
serialize_into_session
and serialize_from_session
.We have to create a module that performs at least three tasks:
1 2 3 4 5 6 7 8 9 10 11 |
|
Devise::Models::RemoteAuthenticatable#remote_authentication
will be used later (in the Warden strategy) to authenticate the resource using the remote webservice. This method performs almost the same function as Devise::Models::DatabaseAuthenticatable#valid_pasword?
in the sense that they both have to return a resource instance if the creedentials are valid or false otherwise.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
We overwrite Devise::Models::ClassMethods#serialize_into_session
and Devise::Models::ClassMethods#serialize_from_session
because their implementation is tied to resources using some kind of database backup. In this methods you just have to return an array with data that you’ll use later to re-build the resource instance.
The full code (with comments) of Devise::Models::RemoteAuthenticatable
is on this gist
Strategies contains the logic used by Warden to authenticate users. They must define an authenticate! method, where the request will be processed. Inside this method you can take several actions:
halt!
which halts the cascading of strategies.fail!
fails the strategy. Calls halt!success!
log in a user.Because of the conventions used by Devise, the strategy name has to be the same as the name of the module used to authenticate the resource.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
The previous code is pretty straightforward. We create a new resource and using Devise::Models::RemoteAuthenticatable#remote_authentication
we authenticate it. If the authentication succeeds we mark the request as valid with success!
.
Gist with the code, and comments, of this strategy.
So, to sum up, this solution is composed of:
Devise::Models::RemoteAuthenticatable
, a module used by Devise to authenticate the resource.Devise::Strategies::RemoteAuthenticatable
, a class implementing a Warden strategy.Finally, don’t forguet to configure Devise (in config/initializers/devise.rb) to use all the stuff we have done here : )
1 2 3 4 |
|
The other day I ran into a problem because of using the same computer for work and personal projects: I was commiting with the same user for both kind of projects, which I don’t want.
I want different user.email
config setting for each type of project but I didn’t want to do it manually.
So I came up with a simple solution. It’s composed of four parts:
Using all this, as you’ll see, each time I clone a work or personal repo I end up with a different value of user.email
depending on the type of project.
Repos for personal and work projects must be contained into separated dirs so they have different config files. This is my layout:
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 |
|
The file .gitconfig.clone
is where you place your specific bits of configuration. The syntax used is the same that you’ll use with git config
For example, the .gitconfig.clone
for my work projects is this:
1
|
|
1 2 3 4 5 6 7 8 9 |
|
When called, this function will look for a file called .gitconfig.clone
in the current directory. If it exists, its lines will be returned (echoed).
And to finish the git alias:
1 2 3 |
|
When this alias is used, git cl REPO_URL
, the bash function will be run to look for the .gitconfig.clone
file. If that file exists its lines will be read and used in git clone --config CONFIG_LINES REPO_URL
. This way, when git initializes the cloned repo it’ll use the config options given with --config
flag.
Currently I’m using this just for the user.email
config setting but it could be used to apply any of the supported config settings.
You can find my gitconfig file and other dot-stuff on my dotfiles repo on Github
]]>Los conceptos que vamos a tratar en este post los ejemplificamos con Backbone. Por si no lo conoces o no tienes muy claro que es, aquí te dejamos una brevisima introducción:
Backbone es uno de los múltiples frameworks Javascript (1 y 2) que implementan el paradigma MVC en el navegador. En Backbone el rol de controlador lo juegan los componentes que sus desarrolladores denominan Views (Backbone.View) y el papel de vistas se implementa con cualquiera de las librerías de templating existentes (Eco, Moustache, etc.). Por lo tanto, una vez dicho esto, ten en cuenta que cuando hablemos de vista probablemente nos refiramos a controladores. Sea como sea, intentaremos ser lo más claros posible :___ )
Actualización: Realmente no está tan claro que Backbone siga el paradigma MVC (1, 2 y 3) pero durante el post seguiremos la convención de Vista =~ Plantilla HTML y Controlador =~ Backbone.View.
En Trabe estamos utilizando/probando Backbone en una aplicación en la que hay vistas que se van a mostrar tanto de manera modal como no modal. Como la lógica de estas vistas es independiente de si se están mostrando de manera modal o no, queremos separar la gestión de la ventana modal de su propio contenido y así facilitar la reutilización/refactorización/mantenimiento del código. Para explicarnos mejor vamos a utilizar el siguiente gráfico:
Habrá una vista de Backbone (ModalView en el gráfico) encargada de gestionar la ventana modal (abrir, cerrar, pelearse con el plugin que “pinta” el modal) y una vista modalizada (ModalizedView) que en el caso del gráfico gestiona un formulario.
Hasta aquí todo va muy bien, pero existe un punto en el que, digamos, chocan las responsibilidades de la ModalView y de la ModalizedView. ¿Quién cierra la vista modal? Si es ModalizedView la que cierra el modal, estamos asignándole lógica que no le corresponde con lo que luego será más difícil de mantener o reutilizar. Así que será ModalView la que se cierre a sí misma; pero ¿cómo le indicamos a la ventana modal que puede cerrarse? Podemos hacerlo utilizando:
El código que utilizaríamos para mostrar la ventana modal sería algo así como:
1 2 3 4 |
|
Ahora veremos cómo implementar ModalizedView y ModalView utilizando cada opción.
La vista a modalizar tiene una referencia a la vista modal. Cuando quiere cerrarla simplemente invoca un método en dicha vista.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
En este caso los problemos que nos encontramos son los siguientes:
La utilización de eventos y promesas comparte ventajas e inconvenientes. Entre las ventajas están:
Y entre las desventajas:
La vista a “modalizar” lanza un evento que la vista modal captura y como consecuencia se cierra.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Por promesas nos referimos a los Deferred/Promise de jQuery. Una promesa es un objeto que “represents the eventual value returned from the single completion of an operation” (CommonJS/Promises).
Las vistas a modalizar tienen disponible una promesa que utilizan para indicar que ya han cumplido con su cometido. Esta promesa será utilizada por la vista modal para determinar cuándo tiene que cerrarse.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Las mejores soluciones son la del evento y la de la promesa. ¿Y entre estas dos? Nos gusta más la promesa porque lleva “de serie” la distinción entre una finalización “exitosa” (resolve/done) y una “fallida” (reject/fail), que en el caso de los modales es bastante común. Además, es un estándar de facto – al menos en jQuery – lo que nos permite aprovechar todas las herramientas asociadas.
]]>