{"id":1771,"date":"2014-12-16T18:34:44","date_gmt":"2014-12-16T18:34:43","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1771"},"modified":"2021-09-03T14:18:31","modified_gmt":"2021-09-03T21:18:31","slug":"ruby-rails-and-couchbase-model-social-application","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/ruby-rails-and-couchbase-model-social-application\/","title":{"rendered":"\u00a1Ruby on Rails y Couchbase-Model para una aplicaci\u00f3n social!"},"content":{"rendered":"<h2>Tambi\u00e9n el uso de HAML, SASS, Bootstrap, y Twitter OmniAuth ...<\/h2>\n<p>Antes de empezar - <a href=\"https:\/\/github.com\/rbin\/rvine\">Aqu\u00ed est\u00e1 el c\u00f3digo de GitHub para esta aplicaci\u00f3n...<\/a><\/p>\n<p>Recientemente tuvimos nuestra tercera conferencia Couchbase San Francisco que, por cierto, fue un gran \u00e9xito y un fant\u00e1stico d\u00eda \/ noche.  En la conferencia, di una sesi\u00f3n de 80 minutos basada en la misma aplicaci\u00f3n de ejemplo que vamos a construir hoy.  El prop\u00f3sito de mi charla fue mostrar c\u00f3mo podemos modelar documentos JSON dentro de Couchbase y utilizar todas las capacidades de Map\/Reduce para construir una aplicaci\u00f3n de extremo a extremo.<\/p>\n<p>Este blog asume conocimientos de Rails y cierto uso del Portal del Desarrollador de Twitter.  Si no has usado Couchbase o la gema Couchbase-Model antes, no te preocupes, te guiar\u00e9 en esa parte, pero merece la pena leerlo. <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Modelo Couchbase<\/a> \u00a1primero!<\/p>\n<p>La idea general detr\u00e1s de esta aplicaci\u00f3n es que los usuarios puedan publicar sus propios v\u00eddeos Vine, para ser votados por el p\u00fablico para ver qui\u00e9n tiene los v\u00eddeos Vine m\u00e1s divertidos a nivel mundial.  Los usuarios deben ser autenticados antes de enviar un Vine, y tenemos que hacer un seguimiento de qu\u00e9 Vine pertenece a qu\u00e9 usuario por medio de ID de referencia. es decir, cada Vine debe tener un User_ID dentro de su documento JSON, para que sepamos a qui\u00e9n pertenece.<\/p>\n<p>As\u00ed que sin m\u00e1s dilaci\u00f3n, vamos a ver c\u00f3mo podemos construir una aplicaci\u00f3n gamificada sobre Couchbase usando Ruby y Rails.  La idea de tener una aplicaci\u00f3n social con una tabla de clasificaci\u00f3n y un elemento competitivo es un caso de uso muy com\u00fan, pero no necesariamente uno que haya sido bien documentado (\u00a1especialmente para nosotros en la comunidad Ruby!) Ahora bien, basta de ch\u00e1chara, \u00a1vamos!<\/p>\n<h3>Requisitos previos:<\/h3>\n<ul>\n<li>Servidor Couchbase 2.0+<\/li>\n<li>Ruby 1.9.3+<\/li>\n<li>Rails 3+<\/li>\n<\/ul>\n<p>En lugar de publicar aqu\u00ed cada una de las gemas de nuestra aplicaci\u00f3n Rails, simplemente <a href=\"https:\/\/github.com\/rbin\/rvine\/blob\/master\/Gemfile\">pulse aqu\u00ed<\/a> para ver mi Gemfile para ver que Ruby Gems necesitamos empaquetar para nuestra aplicaci\u00f3n.<\/p>\n<p>1 nota a hacer aqu\u00ed es mi elecci\u00f3n de servidor Ruby.  Utilizo Puma.  Esto no es necesariamente un beneficio en este peque\u00f1o caso de uso, es m\u00e1s un h\u00e1bito personal.  Puma es un servidor web concurrente para Ruby que arranca en el puerto :9292 por defecto.  Puedes usar cualquier servidor web con el que te sientas c\u00f3modo, y simplemente iniciar tu aplicaci\u00f3n con 'rails s' o 'rails server'.<\/p>\n<p>Ahora, antes de empezar con nuestro c\u00f3digo, vamos a crear un bucket en nuestra instancia de Couchbase llamado 'rvine'.  No es necesario preocuparse por el tama\u00f1o de este bucket, as\u00ed que dependiendo de la cantidad de RAM que tengas asignada a tu cl\u00faster, simplemente dale 200mb m\u00e1s o menos.<\/p>\n<p>As\u00ed que vamos a generar una nueva aplicaci\u00f3n Rails.  Vamos a a\u00f1adir a nuestro comando habitual la bandera '-O'.  Esto es para omitir active_record includes. (No podemos usar active_record con Couchbase, pero para eso tenemos la gema Couchbase-Model).<\/p>\n<p><em>Rails nuevo rvine -O<\/em><\/p>\n<p>Ahora asegur\u00e9monos de que hemos copiado el Gemfile del repositorio enlazado arriba.  La importancia de esto es asegurarnos de que tenemos tanto Couchbase como <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Modelo Couchbase<\/a> incluido.  Couchbase-Model es una abstracci\u00f3n sobre la gema Couchbase que permite patrones de dise\u00f1o similares a Active-Record.  Nos facilita enormemente el trabajo con Rails y Couchbase.  Aseg\u00farate de hacer clic en el enlace anterior y leer los detalles de la gema para obtener m\u00e1s informaci\u00f3n.<\/p>\n<p>Cuando sepamos que tenemos ambas gemas en nuestro Gemfile, ejecutamos 'bundle install'.  Una vez hecho esto, configuramos nuestra aplicaci\u00f3n rails con Couchbase como backend.  Desde tu directorio rails en Terminal, ejecuta el comando:<\/p>\n<p><em>Rails genera couchbase:config<\/em><\/p>\n<p>Esto generar\u00e1 un archivo couchbase.yml en nuestro directorio de configuraci\u00f3n que enlaza nuestra aplicaci\u00f3n con nuestra base de datos.   Sigue adelante y edita ese archivo, e introduce las credenciales de nuestro bucket.  Su archivo de configuraci\u00f3n debe reflejar esto:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">com\u00fan: &amp;com\u00fan<br \/>\nnombre de host: localhost<br \/>\npuerto: 8091<br \/>\nnombre de usuario:<br \/>\ncontrase\u00f1a:<br \/>\npiscina: defaultdevelopment:<br \/>\n&lt; bucket: rvine<\/p>\n<p>prueba:<br \/>\n&lt; bucket: rvine<\/p>\n<p># establezca estas variables de entorno en su servidor de producci\u00f3n<br \/>\nproducci\u00f3n:<br \/>\nnombre de host: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">COUCHBASE_HOST<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\npuerto: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">PUERTO_BASE_COUCH<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\nnombre de usuario: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">COUCHBASE_USERNAME<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\ncontrase\u00f1a: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">COUCHBASE_PASSWORD<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\npiscina: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">'COUCHBASE_POOL'<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\ncubo: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">COUCHBASE_BUCKET<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><\/p>\n<\/div>\n<\/div>\n<p>Bien, una vez hecho esto, deber\u00edamos tener un proyecto Rails barebone conectado a Couchbase como almac\u00e9n de datos backend.  \u00bfParece sencillo? Pues porque Couchbase-Model nos hace la vida 1000 veces m\u00e1s f\u00e1cil a la hora de modelar datos.<\/p>\n<p>Ahora, lo siguiente que tenemos que hacer es configurar nuestro <strong><em>Clases de usuario y autenticaci\u00f3n.<\/em><\/strong><\/p>\n<p>Vamos a crear nuestro modelo de usuario en primer lugar.  Crea el archivo \/app\/models\/user.rb<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\n<p><span style=\"color: #9966cc; font-weight: bold;\">clase<\/span> Usuario <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">Couchbase::Modelo<\/span><\/p>\n<p>atributo <span style=\"color: #ff3333; font-weight: bold;\">:nombre<\/span><br \/>\natributo <span style=\"color: #ff3333; font-weight: bold;\">:twit_username<\/span><br \/>\natributo <span style=\"color: #ff3333; font-weight: bold;\">:avatar<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> <span style=\"color: #0000ff; font-weight: bold;\">auto<\/span>.<span style=\"color: #9900cc;\">find_or_create_from_auth_hash<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>hash<span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\nusuario = Usuario.<span style=\"color: #9900cc;\">buscar_por_id<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>hash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:uid<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">a menos que<\/span> usuario<br \/>\nusuario = Usuario.<span style=\"color: #9900cc;\">crear<\/span>!<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #ff3333; font-weight: bold;\">:id<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> hash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:uid<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span>,<br \/>\n<span style=\"color: #ff3333; font-weight: bold;\">:nombre<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> hash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:info<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:nombre<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span>,<br \/>\n<span style=\"color: #ff3333; font-weight: bold;\">:twit_username<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> hash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:info<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:apodo<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span>,<br \/>\n<span style=\"color: #ff3333; font-weight: bold;\">:avatar<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> hash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:info<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:imagen<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\nusuario<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<\/div>\n<\/div>\n<p>En <strong>atributos<\/strong> en este documento son los campos que deseamos incluir en nuestro documento JSON.  Estamos recogiendo el nombre del usuario, nombre de usuario de Twitter y Avatar.  Necesitamos dar una clave \u00fanica a cada usuario en nuestra base de datos.  En este caso, lo estamos haciendo mediante la recopilaci\u00f3n de Twitter UID del usuario y la creaci\u00f3n de un hash de que para generar una clave para nuestro documento de usuario.  Es importante recordar que la clave de cada documento en nuestra base de datos debe ser \u00fanica.  Tambi\u00e9n, vale la pena se\u00f1alar la clase que hemos creado. Esta clase hace exactamente lo que dice en la lata. Si un usuario existe, lo autentica. Si no, crearlos a partir de los datos de Twitter que recibimos.<\/p>\n<p>Habr\u00e1s notado que hemos elegido usar Twitter-Omniauth para esto, \u00a1para ahorrarnos un mont\u00f3n de tiempo en lugar de escribir una clase Auth desde cero!  Lo primero que hay que hacer es ir a Twitter Dev y coger algunas claves de aplicaci\u00f3n.  Si nunca has hecho esto antes, inicia sesi\u00f3n con tu cuenta de Twitter.  Crea una nueva aplicaci\u00f3n llamada 'rvine' y una vez que lo hayas hecho, se te presentar\u00e1n 2 claves de aplicaci\u00f3n.<\/p>\n<p>Crea un archivo de configuraci\u00f3n en config\/initializers\/omniauth.rb.  Una vez creado este archivo, \u00e1brelo e introduce el siguiente c\u00f3digo:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">Rieles.<span style=\"color: #9900cc;\">aplicaci\u00f3n<\/span>.<span style=\"color: #9900cc;\">config<\/span>.<span style=\"color: #9900cc;\">middleware<\/span>.<span style=\"color: #9900cc;\">utilice<\/span> <span style=\"color: #6666ff; font-weight: bold;\">OmniAuth::Constructor<\/span> <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nproveedor <span style=\"color: #ff3333; font-weight: bold;\">:twitter<\/span>, <span style=\"color: #996600;\">\"CONSUMER_KEY\"<\/span>, <span style=\"color: #996600;\">\"CONSUMER_SECRET\"<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/div>\n<\/div>\n<p>Esto deber\u00eda significar que ya tenemos Omniauth configurado con nuestras claves de aplicaci\u00f3n de Twitter, y casi listo para funcionar.  Lo siguiente que tenemos que hacer es crear una ruta en nuestra aplicaci\u00f3n Rails para gestionar el proceso de autenticaci\u00f3n.  Abrimos nuestro archivo config\/routes.rb e introducimos lo siguiente:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">match <span style=\"color: #996600;\">\/auth\/twitter\/callback<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:to<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #996600;\">sesiones#create<\/span><\/div>\n<\/div>\n<p>Ahora le estamos diciendo a Rails que env\u00ede nuestra llamada de retorno de Twitter Auth'd a nuestro controlador de sesiones.... \u00bfQu\u00e9 controlador de sesiones?   Tenemos que crearlo ahora.<\/p>\n<p>Sigue adelante y crea el archivo app\/<em>controllers\/sessions_controller.rb<\/em><\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #9966cc; font-weight: bold;\">clase<\/span> Controlador de sesiones <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> Controlador de aplicaci\u00f3n<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> crear<br \/>\nusuario = Usuario.<span style=\"color: #9900cc;\">find_or_create_from_auth_hash<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>auth_hash<span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\nsesi\u00f3n<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:user_id<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> = usuario.<span style=\"color: #9900cc;\">id<\/span><br \/>\nflash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:\u00e9xito<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> = <span style=\"color: #996600;\">\"\u00a1Bienvenido al club!\"<\/span><br \/>\nredirect_to dashboard_path<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span>protegido<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> auth_hash<br \/>\nsolicitud.<span style=\"color: #9900cc;\">env<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">omniauth.auth<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<\/div>\n<\/div>\n<p>Como se puede ver en este c\u00f3digo, nuestro m\u00e9todo 'Create' est\u00e1 llamando a la clase que definimos en nuestro User.rb para inicializar una sesi\u00f3n cuando un usuario hace clic para autenticarse desde el frontend, o crear el usuario si a\u00fan no existe.  Una vez autenticado, redirigimos al usuario a su panel de control. (\u00a1Que crearemos pronto!)<\/p>\n<p>A continuaci\u00f3n, vamos a actualizar nuestro <em>application_controller.rb <\/em>para incluir clases de ayuda para nuestra Autenticaci\u00f3n - incluyendo un m\u00e9todo de ayuda para definir un Current_User y un m\u00e9todo de ayuda para asegurar que un Usuario est\u00e1 Registrado.<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #9966cc; font-weight: bold;\">clase<\/span> Controlador de aplicaci\u00f3n <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">ActionController::Base<\/span><br \/>\nproteger_de_falsificaciones<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> \u00a1Autenticar!<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">si<\/span> signed_in?<br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">devolver<\/span> <span style=\"color: #0000ff; font-weight: bold;\">verdadero<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">si no<\/span><br \/>\nflash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:error<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> = <span style=\"color: #996600;\">\"No est\u00e1 autorizado a acceder a esta p\u00e1gina\"<\/span><br \/>\nredirigir_a<span style=\"color: #006600; font-weight: bold;\">(<\/span>ruta_raiz<span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> usuario_actual<br \/>\n<span style=\"color: #0066ff; font-weight: bold;\">@usuario_actual<\/span> <span style=\"color: #006600; font-weight: bold;\">||<\/span>= Usuario.<span style=\"color: #9900cc;\">buscar_por_id<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>sesi\u00f3n<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:user_id<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\nm\u00e9todo_ayudante <span style=\"color: #ff3333; font-weight: bold;\">:usuario_actual<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> signed_in?<br \/>\nUsuario_actual<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\nm\u00e9todo_ayudante <span style=\"color: #ff3333; font-weight: bold;\">:signed_in<\/span>?<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<\/div>\n<\/div>\n<p>A continuaci\u00f3n tenemos que crear el panel de control al que se redirigir\u00e1 a nuestros usuarios una vez autorizados.  Para ello usaremos un comando Rails Generate.<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">rails genera cuadros de mando de controladores<\/div>\n<\/div>\n<p>Ahora, vamos a abrir el archivo <em>app\/controllers\/dashboards_controller.rb<\/em> e introduce lo siguiente:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\n<p><span style=\"color: #9966cc; font-weight: bold;\">clase<\/span> Cuadros de mandoController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> Controlador de aplicaci\u00f3n<\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> Mostrar<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<\/div>\n<\/div>\n<p>Vamos a abrir nuestra vista frontend del Dashboard, y editar eso. En mi caso, va a ser un archivo HAML.  Independientemente de que elijas ERB o HAML, el archivo va a tener pr\u00e1cticamente el mismo aspecto.  En <em>app\/views\/paneles de control<\/em> - basta con crear el archivo show.haml o show.erb.<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #006600; font-weight: bold;\">%<\/span>secci\u00f3n<span style=\"color: #008000; font-style: italic;\">1TP5Bienvenido<\/span><br \/>\n.<span style=\"color: #9900cc;\">p\u00e1gina<\/span><span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span>cabecera<br \/>\n<span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span> <span style=\"color: #9966cc; font-weight: bold;\">si<\/span> signed_in?<br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nHola, <span style=\"color: #008000; font-style: italic;\">#{current_user.name}<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span><span style=\"color: #cc0066; font-weight: bold;\">p<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>img<span style=\"color: #006600; font-weight: bold;\">{<\/span>:src <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> usuario_actual.<span style=\"color: #9900cc;\">avatar<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:alt<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #996600;\">\"Avatar\"<\/span><span style=\"color: #006600; font-weight: bold;\">}<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span><span style=\"color: #cc0066; font-weight: bold;\">p<\/span>= enlace_a<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #996600;\">\"Todas las vides\"<\/span>, <span style=\"color: #996600;\">\"\/vines\"<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span> <span style=\"color: #9966cc; font-weight: bold;\">si no<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nHola, forastero<br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span><span style=\"color: #cc0066; font-weight: bold;\">p<\/span><br \/>\n= enlace_a<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #996600;\">\"Inicia sesi\u00f3n con tu cuenta de twitter\"<\/span>, <span style=\"color: #996600;\">\"\/auth\/twitter\"<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span><span style=\"color: #cc0066; font-weight: bold;\">p<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">&amp;<\/span>nbsp;<\/div>\n<\/div>\n<p>Ahora que ya tenemos nuestro panel de control, tenemos que configurar algunas rutas m\u00e1s, y luego podemos seguir adelante y probar las cosas.  Abrir <em>config\/rutas.rb <\/em>y a\u00f1ade lo siguiente:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">recurso <span style=\"color: #ff3333; font-weight: bold;\">:salpicadero<\/span><\/div>\n<\/div>\n<p>Una vez hecho esto, guarda, ejecuta tu aplicaci\u00f3n y autentif\u00edcate como usuario.<\/p>\n<p>Perfecto. Ahora podemos ver que nuestra Autenticaci\u00f3n funciona, y nuestros Usuarios tienen un Dashboard.  Si abrimos nuestra consola de Couchbase, \u00a1tambi\u00e9n deber\u00edamos ver que se ha creado un Usuario dentro de nuestro bucket de Rvine!<\/p>\n<p>Ahora que tenemos nuestros usuarios y autenticaci\u00f3n en su lugar, vamos a pasar a la parte principal de la aplicaci\u00f3n: \u00a1Los videos de Vine!  Para empezar, vamos a necesitar crear un modelo para Vines.  Ahora, desafortunadamente, Couchbase-Model todav\u00eda no soporta el Generador de rails en esta acci\u00f3n.  As\u00ed que tenemos que crear manualmente\u00a0 <em>\/app\/models\/vine.rb<\/em><\/p>\n<p>Una vez hecho esto, vamos a rellenar lo siguiente:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #cc0066; font-weight: bold;\">requiere<\/span> <span style=\"color: #996600;\">open-uri<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">requiere<\/span> <span style=\"color: #996600;\">uri<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">requiere<\/span> <span style=\"color: #996600;\">nokogiri<\/span><span style=\"color: #9966cc; font-weight: bold;\">clase<\/span> Vid <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">Couchbase::Modelo<\/span><br \/>\ndespu\u00e9s_de_guardar <span style=\"color: #ff3333; font-weight: bold;\">:extraer_v\u00eddeo_url<\/span><\/p>\n<p>pertenece_a <span style=\"color: #ff3333; font-weight: bold;\">:usuario<\/span><\/p>\n<p>atributo <span style=\"color: #ff3333; font-weight: bold;\">:t\u00edtulo<\/span><br \/>\natributo <span style=\"color: #ff3333; font-weight: bold;\">:vine_url<\/span><br \/>\natributo <span style=\"color: #ff3333; font-weight: bold;\">:video_url<\/span><\/p>\n<p><span style=\"color: #008000; font-style: italic;\">#Voting API<\/span><br \/>\natributo <span style=\"color: #ff3333; font-weight: bold;\">:puntuaci\u00f3n<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:por defecto<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #006666;\">1<\/span><\/p>\n<p>valida_presencia_de <span style=\"color: #ff3333; font-weight: bold;\">:t\u00edtulo<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:vine_url<\/span><\/p>\n<p>privado<\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> extraer_v\u00eddeo_url<br \/>\ndoc = Nokogiri<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #cc0066; font-weight: bold;\">abra<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>vine_url<span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">leer<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">auto<\/span>.<span style=\"color: #9900cc;\">video_url<\/span> = doc.<span style=\"color: #9900cc;\">css<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #996600;\">\"fuente\"<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">primero<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">\"src\"<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><br \/>\nsave_without_callbacks<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/p>\n<\/div>\n<\/div>\n<p>Como podemos ver en el c\u00f3digo anterior, estamos incluyendo open-uri, uri, y nokogiri.  Esto se debe a que Vine no tiene una API p\u00fablica, \u00a1pero necesitamos obtener esos v\u00eddeos de alguna manera!   As\u00ed que, con la ayuda de estas librer\u00edas, hemos escrito un script descarado para rastrear la fuente de un v\u00eddeo de Vine y obtener el URI mp4 exacto cuando un usuario introduce la URL de Vine.<\/p>\n<p>La clase <em>extraer_v\u00eddeo_url<\/em> mediante el m\u00e9todo <em>despu\u00e9s_de_guardar<\/em>.  Del c\u00f3digo podemos ver que Nokogiri abre la URL introducida por nuestro usuario al publicar un Vine.  A continuaci\u00f3n, busca la fuente de la p\u00e1gina de Vine para encontrar la l\u00ednea que declara la URI mp4 real de Vine.<\/p>\n<p>Aparte de eso, podemos ver que cada Vine pertenece a un Usuario, tiene atributos para el T\u00edtulo, Vine URL (Introducido por el usuario) y Video URL (mp4 URI real).  Tambi\u00e9n tenemos un atributo Score. (<strong>El atributo m\u00e1s importante). <\/strong>Tenga en cuenta tambi\u00e9n que cada v\u00eddeo comienza con una puntuaci\u00f3n de 1.<\/p>\n<p>Ahora, vamos a generar un controlador y vistas para nuestro modelo Vine. Ejecutar:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">los ra\u00edles generan vides de andamio<\/div>\n<\/div>\n<p>Es posible que en este punto aparezca un error de conflicto diciendo que el modelo ya existe. No te preocupes, simplemente di 'N' para no sobrescribirlo.  Tambi\u00e9n puedes ver un error Couchbase not found.  De nuevo, no te preocupes por esto, como he dicho antes Couchbase-Model no es compatible con el generador de modelos de Rails.<\/p>\n<p>Si todo ha ido seg\u00fan lo previsto, ahora deber\u00eda tener un <em>vines_controller.rb <\/em>y toda una carpeta de vistas para las vides con los archivos frontend HAML o ERB.  Siga adelante y abra <em>vines_controller.rb <\/em>y aseg\u00farese de que refleja la <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/controllers\/vines_controller.rb\">archivo aqu\u00ed<\/a>.<\/p>\n<p>En nuestro archivo de controlador, es posible que haya notado un m\u00e9todo llamado <em>'upvote'. <\/em>\u00a0Este es el mecanismo de votaci\u00f3n para nuestros v\u00eddeos de Vine.  Para terminar la implementaci\u00f3n de este sistema de votaci\u00f3n, y para dar realmente a los v\u00eddeos de Vine un lugar para vivir, abra el archivo <em>app\/views\/vines\/show.haml(o .erb)<\/em><\/p>\n<p>Aseg\u00farese de que relfects el archivo <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/show.html.haml\" target=\"_blank\" rel=\"noopener\">aqu\u00ed<\/a>&#8230;<\/p>\n<p>Antes de que nuestro sistema de votaci\u00f3n funcione completamente, tenemos que a\u00f1adir lo siguiente a nuestro <em>rutas.rb <\/em>archivo<em>:<\/em><\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0 recursos <span style=\"color: #ff3333; font-weight: bold;\">:vines<\/span> <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nmiembro <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nponer <span style=\"color: #ff3333; font-weight: bold;\">:upvote<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">fin<\/span><\/div>\n<\/div>\n<p>Bien, ya podemos mostrar nuestros v\u00eddeos de Vine y el mecanismo de votaci\u00f3n est\u00e1 en marcha.  Lo siguiente que tenemos que hacer es configurar la p\u00e1gina principal de la aplicaci\u00f3n - <strong>La clasificaci\u00f3n<\/strong>\u00a0 Nuestra tabla de clasificaci\u00f3n, a pesar de ser la caracter\u00edstica principal de la aplicaci\u00f3n, es incre\u00edblemente sencilla.  Abre el archivo\u00a0 <em>app\/views\/vines\/index.haml (o .erb)\u00a0 <\/em>y aseg\u00farese de que coincide con el <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/index.html.haml\">c\u00f3digo aqu\u00ed<\/a>.<\/p>\n<p>Ahora bien, si se tratara de una aplicaci\u00f3n Rails relacional normal y corriente, tendr\u00edamos que hacer lo siguiente <strong>debe<\/strong> en teor\u00eda tenemos una clasificaci\u00f3n ya creada, con una lista de cada v\u00eddeo de Vine en nuestra base de datos.\u00a0 <strong>PERO<\/strong> este no es el caso aqu\u00ed.<\/p>\n<p>En Couchbase, tenemos que crear nuestra tabla de clasificaci\u00f3n utilizando <strong>Vistas<\/strong> en Couchbase y utilizando la t\u00e9cnica Map\/Reduce antes de conseguir una tabla de clasificaci\u00f3n que funcione correctamente.  As\u00ed que, \u00a1hag\u00e1moslo!  Antes de continuar, si no has usado Couchbase Views antes de esto, te recomiendo que leas <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/3.x\/admin\/Views\/views-intro.html\">estos documentos<\/a>El objetivo de este art\u00edculo es ofrecerte una buena base sobre qu\u00e9 son las vistas de Couchbase, c\u00f3mo las usamos y facilitarte su uso en esta aplicaci\u00f3n Rails.<\/p>\n<p>Para nuestra aplicaci\u00f3n, necesitamos crear una vista en Couchbase, que muestre cada v\u00eddeo, con su puntuaci\u00f3n y t\u00edtulo.  Tambi\u00e9n necesitan ser ordenados, de forma descendente, por puntuaci\u00f3n para que el v\u00eddeo Vine con la puntuaci\u00f3n m\u00e1s alta est\u00e9 naturalmente en la parte superior de la tabla de clasificaci\u00f3n.<\/p>\n<p>Si has usado Couchbase Views antes, puede que las hayas creado desde la propia consola de administraci\u00f3n.  Las Views se pueden crear desde dentro de la Admin UI, desde cualquiera de nuestros clientes SDK y mediante la REST API.  En este caso, Couchbase-Model tiene una forma \u00fanica y bastante brillante de permitirnos generar Views para nuestra aplicaci\u00f3n. Echa un vistazo a <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model#views-aka-mapreduce-indexes\">estos documentos<\/a> para ver c\u00f3mo se puede hacer, y c\u00f3mo estamos a punto de hacerlo.<\/p>\n<p>En Terminal, simplemente ejecute:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">rails generate couchbase:view vine all<\/div>\n<\/div>\n<p>Ahora, en su\u00a0 <em>app\/modelos <\/em>deber\u00edas tener un nuevo subdirectorio llamado vine, con un subdirectorio llamado all.  Este directorio contiene 2 archivos .js - nuestro map.js y reduce.js.  Por ahora, todo lo que nos interesa es el archivo map.js.  Adelante, \u00e1brelo e introduce lo siguiente:<\/p>\n<div class=\"geshifilter\">\n<div class=\"javascript geshifilter-javascript\" style=\"font-family: monospace;\"><span style=\"color: #003366; font-weight: bold;\">funci\u00f3n<\/span><span style=\"color: #009900;\">(<\/span>doc<span style=\"color: #339933;\">,<\/span> meta<span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span><br \/>\n<span style=\"color: #000066; font-weight: bold;\">si<\/span> <span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">tipo<\/span> <span style=\"color: #339933;\">==<\/span> <span style=\"color: #3366cc;\">\"vid\"<\/span> <span style=\"color: #339933;\">&amp;&amp;<\/span> doc.<span style=\"color: #660066;\">t\u00edtulo<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span><br \/>\nemite<span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">puntuaci\u00f3n<\/span><span style=\"color: #339933;\">,<\/span> doc.<span style=\"color: #660066;\">t\u00edtulo<\/span><span style=\"color: #009900;\">)<\/span><span style=\"color: #339933;\">;<\/span><br \/>\n<span style=\"color: #009900;\">}<\/span><br \/>\n<span style=\"color: #009900;\">}<\/span><\/div>\n<\/div>\n<p>Como podemos ver en esta funci\u00f3n Map, estamos envolviendo todo en una sentencia IF.  Esta es una buena pr\u00e1ctica dentro de Couchbase para comprobar los atributos antes de intentar emitir filas en nuestro \u00edndice.  En este caso, nuestra sentencia IF est\u00e1 asegurando que s\u00f3lo los documentos con el atributo <em>tipo == \"vid\" <\/em>y asegur\u00e1ndose de que la vid tiene un t\u00edtulo.  A continuaci\u00f3n, la funci\u00f3n emit crea una fila en nuestro \u00edndice utilizando el documento <strong>Puntuaci\u00f3n<\/strong> como clave indexada.  Tambi\u00e9n estamos emitiendo el documento T\u00edtulo como valor de salida.<\/p>\n<p>La raz\u00f3n por la que mostramos el <strong>Puntuaci\u00f3n <\/strong>como clave indexada, es que podemos aprovechar la ordenaci\u00f3n Unicode que Couchbase aplica autom\u00e1ticamente a este campo.  En nuestro caso, necesitamos asegurarnos de que nuestra puntuaci\u00f3n es descendente, para empujar el Vine con mayor puntuaci\u00f3n a la parte superior de la tabla de clasificaci\u00f3n.  Esta funci\u00f3n de mapa funcionar\u00e1 bien por s\u00ed sola, y si ejecutas la aplicaci\u00f3n ahora, tendr\u00e1s una lista de videos de Vine, \u00a1pero estar\u00e1n en el orden equivocado!<\/p>\n<p>Es hora de aplicar otra caracter\u00edstica de Couchbase para pulir nuestro Leaderboard y asegurarnos de que funciona como deber\u00eda.  Es hora de <strong>Consultar nuestra vista<\/strong> para crear nuestro producto final.   Una vez m\u00e1s, Couchbase-Model nos permite hacer esto directamente desde nuestro c\u00f3digo Rails.  Abre tu fichero de modelo <em>\u00a0vine.rb \u00a0<\/em>y a\u00f1ade la siguiente l\u00ednea justo encima de la declaraci\u00f3n 'private':<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0ver <span style=\"color: #ff3333; font-weight: bold;\">:todos<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:limit<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #006666;\">10<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:descendente<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #0000ff; font-weight: bold;\">verdadero<\/span><\/div>\n<\/div>\n<p>Este c\u00f3digo no s\u00f3lo es necesario para a\u00f1adir par\u00e1metros de consulta a nuestra Vista, sino que debe a\u00f1adirse a nuestro archivo Vine.rb con o sin par\u00e1metros de consulta para asegurarnos de que nuestra aplicaci\u00f3n sabe qu\u00e9 Vista(s) tiene que utilizar en nuestra aplicaci\u00f3n.  En este caso, podemos ver, no s\u00f3lo estamos definiendo qu\u00e9 vista debe utilizar nuestra aplicaci\u00f3n, sino que tambi\u00e9n hemos a\u00f1adido los par\u00e1metros de consulta:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0<span style=\"color: #ff3333; font-weight: bold;\">:limit<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #006666;\">10<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:descendente<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #0000ff; font-weight: bold;\">verdadero<\/span><\/div>\n<\/div>\n<p>De este modo, limitamos la salida de la vista a 10 resultados y nos aseguramos de que la funci\u00f3n <strong>Puntuaci\u00f3n <\/strong>est\u00e1 en orden descendente.<\/p>\n<p>Ya est\u00e1.  Si rellenas tu base de datos con unos cuantos v\u00eddeos de Vine, deber\u00edas ver que tienes una aplicaci\u00f3n Rate my Vine completamente funcional.  A lo largo de este art\u00edculo hemos visto c\u00f3mo podemos modelar datos con la gema Couchbase-Model de Couchbase Rails, hemos visto c\u00f3mo podemos usar Views en Couchbase para crear aplicaciones interactivas, y hemos visto c\u00f3mo podemos hacer Query en esas Views para obtener subconjuntos espec\u00edficos de datos para usar en nuestra aplicaci\u00f3n.<\/p>\n<p>Me doy cuenta de que no todo lo que hay dentro de la aplicaci\u00f3n est\u00e1 en este art\u00edculo (estilos, etc.), pero eso no tiene importancia.  Espero haber cubierto los puntos principales (Couchbase-Model, Modelado de Documentos, Vistas y Consultas) lo suficientemente bien como para que sientas que puedes empezar tu propia aplicaci\u00f3n Rails usando la gema Couchbase-Model.<\/p>\n<p>Si es usted londinense, \u00fanase a nuestro <a href=\"https:\/\/www.meetup.com\/Couchbase-London\/\">Meetup de Couchbase en Londres<\/a> ya que en las pr\u00f3ximas semanas organizaremos eventos en los que se tratar\u00e1n en detalle el modelado de documentos, Couchbase Mobile y muchos otros temas.<\/p>\n<p>Si has le\u00eddo hasta aqu\u00ed, \u00a1s\u00f3lo puedo felicitarte! S\u00e9 que ha sido un art\u00edculo LARGO.  Si tienes alguna pregunta, como siempre, estar\u00e9 encantada de responderte.  P\u00e9game en Twitter en <em><strong><a href=\"https:\/\/twitter.com\/rbin\">@Rbin<\/a><\/strong><\/em> y env\u00edame cualquier pregunta.<\/p>\n<p><strong>Robin Johnson<br \/>\nDefensor del Desarrollador, Europa.<\/strong><\/p>","protected":false},"excerpt":{"rendered":"<p>Also using HAML, SASS, Bootstrap, And Twitter OmniAuth&#8230; Before we start \u2013 Here\u2019s the GitHub code for this App\u2026 We recently had our 3rd Couchbase San Francisco conference which, by the way, \u00a0was a great success and a fantastic day [&hellip;]<\/p>","protected":false},"author":2,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1816,9407,2201],"tags":[1301,1395],"ppma_author":[8968],"class_list":["post-1771","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-couchbase-server","category-ruby","category-tools-sdks","tag-competitive","tag-rails"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Ruby on Rails and Couchbase-Model for a Social Application!<\/title>\n<meta name=\"description\" content=\"Learn how to model data with the Couchbase Rails gem Couchbase-Model and how we to Query Views to get specific subsets of data for use in our application.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/ruby-rails-and-couchbase-model-social-application\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruby on Rails and Couchbase-Model for a Social Application!\" \/>\n<meta property=\"og:description\" content=\"Learn how to model data with the Couchbase Rails gem Couchbase-Model and how we to Query Views to get specific subsets of data for use in our application.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/ruby-rails-and-couchbase-model-social-application\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T18:34:43+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-09-03T21:18:31+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"The Couchbase Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"The Couchbase Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"15 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\"},\"author\":{\"name\":\"The Couchbase Team\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/764f4a6771ee19bc7af70b70a326fb93\"},\"headline\":\"Ruby on Rails and Couchbase-Model for a Social Application!\",\"datePublished\":\"2014-12-16T18:34:43+00:00\",\"dateModified\":\"2021-09-03T21:18:31+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\"},\"wordCount\":3052,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"Competitive\",\"Rails\"],\"articleSection\":[\"Application Design\",\"Couchbase Server\",\"Ruby\",\"Tools &amp; SDKs\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\",\"name\":\"Ruby on Rails and Couchbase-Model for a Social Application!\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T18:34:43+00:00\",\"dateModified\":\"2021-09-03T21:18:31+00:00\",\"description\":\"Learn how to model data with the Couchbase Rails gem Couchbase-Model and how we to Query Views to get specific subsets of data for use in our application.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruby on Rails and Couchbase-Model for a Social Application!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/764f4a6771ee19bc7af70b70a326fb93\",\"name\":\"The Couchbase Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/7befc37d02226b59499817eafdec60c3\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b4c18c758421903398e84d6c9560f319f39c665798d7d23e6a6f9dff8a8f984e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b4c18c758421903398e84d6c9560f319f39c665798d7d23e6a6f9dff8a8f984e?s=96&d=mm&r=g\",\"caption\":\"The Couchbase Team\"},\"description\":\"Jennifer Garcia is a Senior Web Manager at Couchbase Inc. As the website manager, Jennifer has overall responsibility for the website properties including design, implementation, content, and performance.\",\"sameAs\":[\"https:\/\/www.couchbase.com\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/jennifer-garcia\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"\u00a1Ruby on Rails y Couchbase-Model para una aplicaci\u00f3n social!","description":"Aprende a modelar datos con la gema Couchbase-Model de Couchbase Rails y a consultar vistas para obtener subconjuntos espec\u00edficos de datos para su uso en nuestra aplicaci\u00f3n.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/ruby-rails-and-couchbase-model-social-application\/","og_locale":"es_MX","og_type":"article","og_title":"Ruby on Rails and Couchbase-Model for a Social Application!","og_description":"Learn how to model data with the Couchbase Rails gem Couchbase-Model and how we to Query Views to get specific subsets of data for use in our application.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/ruby-rails-and-couchbase-model-social-application\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T18:34:43+00:00","article_modified_time":"2021-09-03T21:18:31+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"The Couchbase Team","twitter_card":"summary_large_image","twitter_misc":{"Written by":"The Couchbase Team","Est. reading time":"15 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/"},"author":{"name":"The Couchbase Team","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/764f4a6771ee19bc7af70b70a326fb93"},"headline":"Ruby on Rails and Couchbase-Model for a Social Application!","datePublished":"2014-12-16T18:34:43+00:00","dateModified":"2021-09-03T21:18:31+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/"},"wordCount":3052,"commentCount":4,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["Competitive","Rails"],"articleSection":["Application Design","Couchbase Server","Ruby","Tools &amp; SDKs"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/","url":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/","name":"\u00a1Ruby on Rails y Couchbase-Model para una aplicaci\u00f3n social!","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T18:34:43+00:00","dateModified":"2021-09-03T21:18:31+00:00","description":"Aprende a modelar datos con la gema Couchbase-Model de Couchbase Rails y a consultar vistas para obtener subconjuntos espec\u00edficos de datos para su uso en nuestra aplicaci\u00f3n.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Ruby on Rails and Couchbase-Model for a Social Application!"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/764f4a6771ee19bc7af70b70a326fb93","name":"El equipo de Couchbase","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/7befc37d02226b59499817eafdec60c3","url":"https:\/\/secure.gravatar.com\/avatar\/b4c18c758421903398e84d6c9560f319f39c665798d7d23e6a6f9dff8a8f984e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b4c18c758421903398e84d6c9560f319f39c665798d7d23e6a6f9dff8a8f984e?s=96&d=mm&r=g","caption":"The Couchbase Team"},"description":"Jennifer Garcia es Gerente Senior de Web en Couchbase Inc. Como responsable del sitio web, Jennifer tiene la responsabilidad general de las propiedades del sitio web, incluido el dise\u00f1o, la implementaci\u00f3n, el contenido y el rendimiento.","sameAs":["https:\/\/www.couchbase.com"],"url":"https:\/\/www.couchbase.com\/blog\/es\/author\/jennifer-garcia\/"}]}},"authors":[{"term_id":8968,"user_id":2,"is_guest":0,"slug":"jennifer-garcia","display_name":"The Couchbase Team","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/b4c18c758421903398e84d6c9560f319f39c665798d7d23e6a6f9dff8a8f984e?s=96&d=mm&r=g","author_category":"","last_name":"Garcia","first_name":"Jennifer","job_title":"","user_url":"https:\/\/www.couchbase.com","description":"Jennifer Garcia es Gerente Senior de Web en Couchbase Inc. Como responsable del sitio web, Jennifer tiene la responsabilidad general de las propiedades del sitio web, incluido el dise\u00f1o, la implementaci\u00f3n, el contenido y el rendimiento."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/1771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=1771"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/1771\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=1771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=1771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=1771"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=1771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}