{"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\/pt\/ruby-rails-and-couchbase-model-social-application\/","title":{"rendered":"Ruby on Rails e Couchbase-Model para um aplicativo social!"},"content":{"rendered":"<h2>Tamb\u00e9m usando HAML, SASS, Bootstrap e Twitter OmniAuth...<\/h2>\n<p>Antes de come\u00e7armos - <a href=\"https:\/\/github.com\/rbin\/rvine\">Aqui est\u00e1 o c\u00f3digo do GitHub para este aplicativo...<\/a><\/p>\n<p>Recentemente, tivemos nossa terceira confer\u00eancia Couchbase em S\u00e3o Francisco, que, a prop\u00f3sito, foi um grande sucesso e um dia e uma noite fant\u00e1sticos.  Na confer\u00eancia, apresentei uma sess\u00e3o de 80 minutos com base no aplicativo de exemplo que vamos criar hoje.  O objetivo da minha palestra foi mostrar como podemos modelar documentos JSON no Couchbase e utilizar todos os recursos de Map\/Reduce para criar um aplicativo de ponta a ponta.<\/p>\n<p>Este blog pressup\u00f5e conhecimento de Rails e algum uso do Twitter Developer Portal.  Se voc\u00ea nunca usou o Couchbase ou a gem Couchbase-Model antes, n\u00e3o se preocupe, eu o orientarei nessa parte, mas vale a pena ler sobre <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Modelo Couchbase<\/a> Primeiro!<\/p>\n<p>A ideia geral por tr\u00e1s desse aplicativo \u00e9 que os usu\u00e1rios possam publicar seus pr\u00f3prios v\u00eddeos do Vine, que ser\u00e3o votados pelo p\u00fablico para ver quem tem os v\u00eddeos mais engra\u00e7ados do Vine em todo o mundo.  Os usu\u00e1rios devem ser autenticados antes de enviar um Vine, e precisamos controlar qual Vine pertence a qual usu\u00e1rio por meio de IDs referenciais. Ou seja, cada Vine deve ter um User_ID em seu documento JSON, para que saibamos a quem ele pertence.<\/p>\n<p>Portanto, sem mais hesita\u00e7\u00f5es, vamos nos aprofundar e ver como podemos criar um aplicativo gamificado sobre o Couchbase usando Ruby e Rails.  A ideia de ter um aplicativo social com uma tabela de classifica\u00e7\u00e3o e um elemento competitivo \u00e9 um caso de uso muito comum, mas n\u00e3o necessariamente bem documentado (especialmente para n\u00f3s da comunidade Ruby!).<\/p>\n<h3>Pr\u00e9-requisitos:<\/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>Em vez de publicar cada gem individual do nosso aplicativo Rails aqui, basta <a href=\"https:\/\/github.com\/rbin\/rvine\/blob\/master\/Gemfile\">clique aqui<\/a> para visualizar meu Gemfile e ver quais Ruby Gems precisamos empacotar para nosso aplicativo.<\/p>\n<p>Uma observa\u00e7\u00e3o a ser feita aqui \u00e9 minha escolha de servidor Ruby.  Estou usando o Puma.  Isso n\u00e3o \u00e9 necessariamente uma vantagem nesse pequeno caso de uso, \u00e9 mais um h\u00e1bito pessoal.  O Puma \u00e9 um servidor da Web concorrente e com threads para Ruby que inicia na porta :9292 por padr\u00e3o.  Voc\u00ea pode usar qualquer servidor Web com o qual se sinta confort\u00e1vel e simplesmente iniciar seu aplicativo com 'rails s' ou 'rails server'.<\/p>\n<p>Agora, antes de come\u00e7armos com nosso c\u00f3digo, vamos criar um bucket em nossa inst\u00e2ncia do Couchbase chamado \"rvine\".  N\u00e3o \u00e9 necess\u00e1rio se preocupar com o dimensionamento desse bucket, portanto, dependendo da quantidade de RAM alocada no cluster, basta fornecer 200 MB ou mais.<\/p>\n<p>Ent\u00e3o, vamos gerar um novo aplicativo Rails.  Vamos acrescentar ao nosso comando usual o sinalizador '-O'.  Isso serve para ignorar as inclus\u00f5es do active_record. (N\u00e3o podemos usar o active_record com o Couchbase, mas \u00e9 por isso que temos a gem Couchbase-Model!)<\/p>\n<p><em>Trilhos novos rvine -O<\/em><\/p>\n<p>Agora, ent\u00e3o, vamos nos certificar de que voc\u00ea copiou o Gemfile do reposit\u00f3rio vinculado acima.  A import\u00e2ncia disso \u00e9 garantir que tenhamos o Couchbase e o <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Modelo Couchbase<\/a> empacotado.  O Couchbase-Model \u00e9 uma abstra\u00e7\u00e3o sobre a gem do Couchbase que permite padr\u00f5es de design semelhantes aos do Active-Record.  Isso torna muito f\u00e1cil para n\u00f3s come\u00e7armos a trabalhar com o Rails e o Couchbase.  N\u00e3o deixe de clicar no link acima e ler os detalhes da gem para saber mais.<\/p>\n<p>Quando soubermos que temos as duas gemas em nosso Gemfile, execute \"bundle install\".  Depois de fazer isso, configuramos nosso aplicativo rails com o Couchbase como backend.  No diret\u00f3rio do rails, no Terminal, execute o comando:<\/p>\n<p><em>Rails geram couchbase:config<\/em><\/p>\n<p>Isso gerar\u00e1 um arquivo couchbase.yml em nosso diret\u00f3rio de configura\u00e7\u00e3o que vincula nosso aplicativo ao backend do banco de dados.   V\u00e1 em frente, edite esse arquivo e insira nossas credenciais de bucket.  Seu arquivo de configura\u00e7\u00e3o deve refletir isso:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">comum: &amp;comum<br \/>\nNome do host: localhost<br \/>\nporto: 8091<br \/>\nnome de usu\u00e1rio:<br \/>\nsenha:<br \/>\npool: defaultdevelopment:<br \/>\n&lt; bucket: rvine<\/p>\n<p>teste:<br \/>\n&lt; bucket: rvine<\/p>\n<p># defina estas vari\u00e1veis de ambiente em seu servidor de produ\u00e7\u00e3o<br \/>\nprodu\u00e7\u00e3o:<br \/>\nnome do 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 \/>\nporto: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">'COUCHBASE_PORT'<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\nnome de usu\u00e1rio: <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 \/>\nsenha: <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 \/>\nbalde: <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>Ok, agora que isso foi feito, devemos ter um projeto Rails barebone, que est\u00e1 conectado ao Couchbase como seu armazenamento de dados de backend.  Parece simples? Isso \u00e9 porque o Couchbase-Model torna nossa vida 1000 vezes mais f\u00e1cil quando se trata de modelagem de dados!<\/p>\n<p>Agora, a pr\u00f3xima coisa que precisamos fazer \u00e9 configurar nosso <strong><em>Classes de usu\u00e1rio e autentica\u00e7\u00e3o.<\/em><\/strong><\/p>\n<p>Primeiro, vamos criar nosso modelo de usu\u00e1rio.  Crie o arquivo \/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;\">classe<\/span> Usu\u00e1rio <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;\">:nome<\/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;\">aut\u00f4nomo<\/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 \/>\nusu\u00e1rio = User.<span style=\"color: #9900cc;\">find_by_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> usu\u00e1rio<br \/>\nusu\u00e1rio = User.<span style=\"color: #9900cc;\">criar<\/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;\">:nome<\/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;\">:nome<\/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;\">:nickname<\/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;\">:imagem<\/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;\">final<\/span><br \/>\nusu\u00e1rio<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<\/div>\n<\/div>\n<p>O <strong>atributos<\/strong> neste documento s\u00e3o os campos que desejamos incluir em nosso documento JSON.  Estamos coletando o nome do usu\u00e1rio, o nome de usu\u00e1rio do Twitter e o avatar.  Precisamos fornecer uma chave exclusiva para cada usu\u00e1rio em nosso banco de dados.  Nesse caso, estamos fazendo isso coletando o UID do Twitter do usu\u00e1rio e criando um hash a partir dele para gerar uma chave para o nosso documento User.  \u00c9 importante lembrar que a chave de cada documento em nosso banco de dados deve ser exclusiva.  Al\u00e9m disso, vale a pena observar a classe que criamos. 'find_or_create_from_auth_hash' Essa classe est\u00e1 fazendo exatamente o que diz na lata! Se existir um usu\u00e1rio, fa\u00e7a a autentica\u00e7\u00e3o dele. Se n\u00e3o existir, criamos o usu\u00e1rio com base nos detalhes do Twitter que recebemos.<\/p>\n<p>Voc\u00ea deve ter notado que optamos por usar o Twitter-Omniauth para isso, para economizar muito tempo em vez de escrever uma classe Auth do zero!  A primeira coisa a fazer aqui \u00e9 ir at\u00e9 o Twitter Dev e pegar algumas chaves de aplicativo!  Se voc\u00ea nunca fez isso antes, fa\u00e7a login com sua conta do Twitter.  Crie um novo aplicativo chamado \"rvine\" e, depois de fazer isso, voc\u00ea receber\u00e1 duas chaves de aplicativo.<\/p>\n<p>Crie um arquivo de configura\u00e7\u00e3o em config\/initializers\/omniauth.rb.  Depois de criar esse arquivo, abra-o e insira o seguinte c\u00f3digo:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">Trilhos.<span style=\"color: #9900cc;\">aplicativo<\/span>.<span style=\"color: #9900cc;\">configura\u00e7\u00e3o<\/span>.<span style=\"color: #9900cc;\">middleware<\/span>.<span style=\"color: #9900cc;\">uso<\/span> <span style=\"color: #6666ff; font-weight: bold;\">OmniAuth::Construtor<\/span> <span style=\"color: #9966cc; font-weight: bold;\">fazer<\/span><br \/>\nprovedor <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;\">final<\/span><\/div>\n<\/div>\n<p>Isso deve significar que agora temos o Omniauth configurado com as chaves do nosso aplicativo do Twitter e quase pronto para ser usado.  A pr\u00f3xima coisa que precisamos fazer \u00e9 criar uma rota em nosso aplicativo Rails para lidar com o processo de autentica\u00e7\u00e3o.  Ent\u00e3o, vamos abrir nosso arquivo config\/routes.rb e digitar o seguinte:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">partida <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;\">'sessions#create'<\/span><\/div>\n<\/div>\n<p>Agora, estamos dizendo ao Rails para enviar nosso retorno de chamada do Twitter Auth'd para nosso controlador de sess\u00f5es.... Que controlador de sess\u00f5es?   Precisamos cri\u00e1-lo agora.<\/p>\n<p>V\u00e1 em frente e crie o arquivo 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;\">classe<\/span> SessionsController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> Controlador de aplicativos<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> criar<br \/>\nusu\u00e1rio = User.<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 \/>\nsess\u00e3o<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> = usu\u00e1rio.<span style=\"color: #9900cc;\">id<\/span><br \/>\nflash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:sucesso<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> = <span style=\"color: #996600;\">\"Bem-vindo ao clube!\"<\/span><br \/>\nredirect_to dashboard_path<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span>protegida<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> auth_hash<br \/>\nsolicita\u00e7\u00e3o.<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;\">final<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<\/div>\n<\/div>\n<p>Como voc\u00ea pode ver nesse c\u00f3digo, nosso m\u00e9todo \"Create\" est\u00e1 chamando a classe que definimos em nosso User.rb para inicializar uma sess\u00e3o quando um usu\u00e1rio clica para se autenticar no frontend ou criar o usu\u00e1rio se ele ainda n\u00e3o existir.  Uma vez autenticado, estamos redirecionando o usu\u00e1rio para o seu painel. (Que criaremos em breve!)<\/p>\n<p>Em seguida, vamos atualizar nosso <em>application_controller.rb <\/em>para incluir classes auxiliares para nossa autentica\u00e7\u00e3o, inclusive um m\u00e9todo auxiliar para definir um Current_User e um m\u00e9todo auxiliar para garantir que um usu\u00e1rio esteja conectado.<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #9966cc; font-weight: bold;\">classe<\/span> Controlador de aplicativos <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">ActionController::Base<\/span><br \/>\nproteger_de_falsifica\u00e7\u00e3o<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> autenticar!<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">se<\/span> signed_in?<br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">retorno<\/span> <span style=\"color: #0000ff; font-weight: bold;\">verdadeiro<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">mais<\/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;\">\"Voc\u00ea n\u00e3o est\u00e1 autorizado a acessar esta p\u00e1gina\"<\/span><br \/>\nredirect_to<span style=\"color: #006600; font-weight: bold;\">(<\/span>caminho_da_raiz<span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> usu\u00e1rio_atual<br \/>\n<span style=\"color: #0066ff; font-weight: bold;\">@current_user<\/span> <span style=\"color: #006600; font-weight: bold;\">||<\/span>= Usu\u00e1rio.<span style=\"color: #9900cc;\">find_by_id<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>sess\u00e3o<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;\">final<\/span><br \/>\nm\u00e9todo_ajudante <span style=\"color: #ff3333; font-weight: bold;\">:current_user<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> signed_in?<br \/>\n!!current_user<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><br \/>\nm\u00e9todo_ajudante <span style=\"color: #ff3333; font-weight: bold;\">:signed_in<\/span>?<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<\/div>\n<\/div>\n<p>Em seguida, precisamos criar o Dashboard para o qual nossos usu\u00e1rios ser\u00e3o redirecionados ap\u00f3s a autoriza\u00e7\u00e3o.  Para isso, vamos usar um comando Rails Generate.<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">rails geram pain\u00e9is de controle<\/div>\n<\/div>\n<p>Agora, vamos abrir o arquivo <em>app\/controladores\/dashboards_controller.rb<\/em> e digite o seguinte:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\n<p><span style=\"color: #9966cc; font-weight: bold;\">classe<\/span> DashboardsController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> Controlador de aplicativos<\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> show<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<\/div>\n<\/div>\n<p>Vamos abrir nossa visualiza\u00e7\u00e3o de front-end do Dashboard e edit\u00e1-la. No meu caso, ser\u00e1 um arquivo HAML.  Independentemente de voc\u00ea escolher ERB ou HAML, o arquivo ter\u00e1 praticamente a mesma apar\u00eancia!  Em <em>app\/views\/dashboards<\/em> - basta criar o arquivo show.haml ou 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>se\u00e7\u00e3o<span style=\"color: #008000; font-style: italic;\">1TP5Bem-vindo<\/span><br \/>\n.<span style=\"color: #9900cc;\">p\u00e1gina<\/span><span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span>cabe\u00e7alho<br \/>\n<span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span> <span style=\"color: #9966cc; font-weight: bold;\">se<\/span> signed_in?<br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nOl\u00e1, <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>imagem<span style=\"color: #006600; font-weight: bold;\">{<\/span>:src <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> current_user.<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>= link_to<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #996600;\">\"Todas as videiras\"<\/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;\">mais<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nOl\u00e1, estranho<br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span><span style=\"color: #cc0066; font-weight: bold;\">p<\/span><br \/>\n= link_to<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #996600;\">\"Entre com sua conta do 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>Agora que j\u00e1 temos nosso painel de controle, precisamos configurar mais alguns roteamentos e, em seguida, podemos testar as coisas!  Abra o <em>config\/routes.rb <\/em>e adicione o seguinte:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">recurso <span style=\"color: #ff3333; font-weight: bold;\">:dashboard<\/span><\/div>\n<\/div>\n<p>Depois de fazer isso, salve, execute o aplicativo e autentique-se como um usu\u00e1rio.<\/p>\n<p>\u00d3timo! Agora podemos ver que nossa autentica\u00e7\u00e3o funciona e que nossos usu\u00e1rios t\u00eam um painel.  Se abrirmos o console do Couchbase, tamb\u00e9m veremos que um usu\u00e1rio foi criado dentro do nosso bucket do Rvine!<\/p>\n<p>Agora que j\u00e1 temos os usu\u00e1rios e a autentica\u00e7\u00e3o instalados, vamos passar para a parte principal do aplicativo: Os v\u00eddeos do Vine!  Para come\u00e7ar, precisaremos criar um modelo para os Vines.  Infelizmente, o Couchbase-Model ainda n\u00e3o \u00e9 compat\u00edvel com o rails Generator nessa a\u00e7\u00e3o.  Portanto, precisamos criar manualmente\u00a0 <em>\/app\/models\/vine.rb<\/em><\/p>\n<p>Depois de fazer isso, vamos preencher o seguinte:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #cc0066; font-weight: bold;\">exigir<\/span> <span style=\"color: #996600;\">'open-uri'<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">exigir<\/span> <span style=\"color: #996600;\">'uri'<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">exigir<\/span> <span style=\"color: #996600;\">\"nokogiri<\/span><span style=\"color: #9966cc; font-weight: bold;\">classe<\/span> Videira <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">Couchbase::Modelo<\/span><br \/>\nafter_save <span style=\"color: #ff3333; font-weight: bold;\">:extract_video_url<\/span><\/p>\n<p>pertence_a <span style=\"color: #ff3333; font-weight: bold;\">:usu\u00e1rio<\/span><\/p>\n<p>atributo <span style=\"color: #ff3333; font-weight: bold;\">:title<\/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;\">:score<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:default<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #006666;\">1<\/span><\/p>\n<p>validates_presence_of <span style=\"color: #ff3333; font-weight: bold;\">:title<\/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> extract_video_url<br \/>\ndoc = Nokogiri<span style=\"color: #006600; font-weight: bold;\">(<\/span><span style=\"color: #cc0066; font-weight: bold;\">aberto<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>vine_url<span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">ler<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">aut\u00f4nomo<\/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;\">\"fonte\"<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">primeiro<\/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;\">final<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/p>\n<\/div>\n<\/div>\n<p>Como podemos ver no c\u00f3digo acima, estamos incluindo open-uri, uri e nokogiri.  Isso ocorre porque o Vine n\u00e3o tem uma API p\u00fablica, mas precisamos obter esses v\u00eddeos de alguma forma!   Assim, com a ajuda dessas bibliotecas, escrevemos um script atrevido para extrair a fonte de um v\u00eddeo do Vine e pegar o URI mp4 exato quando um usu\u00e1rio digita o URL do Vine.<\/p>\n<p>A classe <em>extract_video_url<\/em> \u00e9 chamado usando o m\u00e9todo <em>after_save<\/em>.  Pelo c\u00f3digo, podemos ver que o Nokogiri est\u00e1 abrindo o URL inserido pelo usu\u00e1rio ao postar um Vine.  Em seguida, ele pesquisa a fonte da p\u00e1gina do Vine para encontrar a linha que declara o URI mp4 real do Vine.<\/p>\n<p>Al\u00e9m disso, podemos ver que cada Vine pertence a um usu\u00e1rio, tem atributos para o t\u00edtulo, URL do Vine (inserido pelo usu\u00e1rio) e URL do v\u00eddeo (URI mp4 real).  Tamb\u00e9m temos um atributo Score. (<strong>O atributo mais importante). <\/strong>Observe tamb\u00e9m que estamos configurando cada v\u00eddeo para come\u00e7ar com uma pontua\u00e7\u00e3o de 1.<\/p>\n<p>Agora, vamos gerar um controlador e exibi\u00e7\u00f5es para o nosso modelo Vine. Executar:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">trilhos geram cip\u00f3s de andaimes<\/div>\n<\/div>\n<p>Nesse momento, voc\u00ea pode receber um erro de conflito dizendo que o modelo j\u00e1 existe. N\u00e3o se preocupe, basta dizer \"N\" para n\u00e3o sobrescrev\u00ea-lo.  Voc\u00ea tamb\u00e9m poder\u00e1 ver um erro Couchbase not found (Couchbase n\u00e3o encontrado).  Novamente, n\u00e3o se preocupe com isso, pois, como afirmei acima, o Couchbase-Model n\u00e3o \u00e9 compat\u00edvel com o gerador de modelos do Rails.<\/p>\n<p>Se tudo correu conforme o planejado, agora voc\u00ea deve ter um <em>vines_controller.rb <\/em>e uma pasta inteira de visualiza\u00e7\u00f5es para vinhas com os arquivos HAML ou ERB de front-end.  V\u00e1 em frente e abra o <em>vines_controller.rb <\/em>e certifique-se de que ele reflita o <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/controllers\/vines_controller.rb\">arquivo aqui<\/a>.<\/p>\n<p>Em nosso arquivo de controle, voc\u00ea deve ter notado um m\u00e9todo chamado <em>'upvote'. <\/em>\u00a0Esse \u00e9 o mecanismo de vota\u00e7\u00e3o para nossos v\u00eddeos do Vine.  Para concluir a implementa\u00e7\u00e3o desse sistema de vota\u00e7\u00e3o e realmente dar aos v\u00eddeos do Vine um lugar para morar, abra o arquivo <em>app\/views\/vines\/show.haml(ou .erb)<\/em><\/p>\n<p>Certifique-se de que o arquivo seja afetado <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/show.html.haml\" target=\"_blank\" rel=\"noopener\">encontrado aqui<\/a>&#8230;<\/p>\n<p>Antes que nosso sistema de vota\u00e7\u00e3o funcione completamente, precisamos adicionar o seguinte ao nosso <em>rotas.rb <\/em>arquivo<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;\">fazer<\/span><br \/>\nmembro <span style=\"color: #9966cc; font-weight: bold;\">fazer<\/span><br \/>\ncolocar <span style=\"color: #ff3333; font-weight: bold;\">:upvote<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">final<\/span><\/div>\n<\/div>\n<p>Ok, agora nossos v\u00eddeos do Vine podem ser exibidos e o mecanismo de vota\u00e7\u00e3o est\u00e1 funcionando!  A pr\u00f3xima coisa que precisamos fazer \u00e9 configurar a p\u00e1gina principal do aplicativo - <strong>A tabela de classifica\u00e7\u00e3o!<\/strong>\u00a0 Nossa tabela de classifica\u00e7\u00e3o, embora seja o principal recurso do aplicativo, \u00e9 incrivelmente simples.  Abra o arquivo\u00a0 <em>app\/views\/vines\/index.haml (ou .erb)\u00a0 <\/em>e verifique se ele corresponde ao <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/index.html.haml\">c\u00f3digo aqui<\/a>.<\/p>\n<p>Agora, se este fosse um aplicativo Rails relacional comum, n\u00f3s <strong>deve<\/strong> em teoria, temos uma tabela de classifica\u00e7\u00e3o j\u00e1 criada, listando cada v\u00eddeo do Vine em nosso banco de dados.\u00a0 <strong>MAS<\/strong> Esse n\u00e3o \u00e9 o caso aqui.<\/p>\n<p>No Couchbase, precisamos criar nossa tabela de classifica\u00e7\u00e3o usando <strong>Visualiza\u00e7\u00f5es<\/strong> no Couchbase e utilizando a t\u00e9cnica Map\/Reduce antes de obtermos uma tabela de classifica\u00e7\u00e3o que realmente funcione corretamente!  Ent\u00e3o, vamos fazer isso!  Antes de prosseguirmos, se voc\u00ea n\u00e3o tiver usado as visualiza\u00e7\u00f5es do Couchbase antes disso, recomendo que leia <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/3.x\/admin\/Views\/views-intro.html\">esses documentos<\/a>O objetivo \u00e9 fornecer a voc\u00ea um pouco de conhecimento sobre o que s\u00e3o as visualiza\u00e7\u00f5es do Couchbase, como as usamos e para facilitar o uso delas neste aplicativo Rails.<\/p>\n<p>Para o nosso aplicativo, precisamos criar uma visualiza\u00e7\u00e3o no Couchbase que produza cada v\u00eddeo do Vine, com sua pontua\u00e7\u00e3o e t\u00edtulo.  Eles tamb\u00e9m precisam ser ordenados, de forma decrescente, por Score, para que o v\u00eddeo do Vine com a pontua\u00e7\u00e3o mais alta fique naturalmente no topo da tabela de classifica\u00e7\u00e3o.<\/p>\n<p>SE voc\u00ea j\u00e1 usou as visualiza\u00e7\u00f5es do Couchbase antes, talvez as tenha criado no pr\u00f3prio console de administra\u00e7\u00e3o.  As visualiza\u00e7\u00f5es podem ser criadas a partir da interface do usu\u00e1rio do administrador, de qualquer um dos nossos clientes SDK e por meio da API REST.  Nesse caso, o Couchbase-Model tem uma maneira \u00fanica e brilhante de nos permitir gerar visualiza\u00e7\u00f5es para nosso aplicativo. D\u00ea uma olhada r\u00e1pida em <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model#views-aka-mapreduce-indexes\">esses documentos<\/a> para ver como isso pode ser feito e como estamos prestes a faz\u00ea-lo.<\/p>\n<p>No Terminal, basta executar:<\/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>Agora, em seu\u00a0 <em>aplicativo\/modelos <\/em>voc\u00ea dever\u00e1 ter um novo subdiret\u00f3rio chamado vine, com um subdiret\u00f3rio chamado all.  Esse diret\u00f3rio cont\u00e9m dois arquivos .js: o map.js e o reduce.js.  Por enquanto, s\u00f3 estamos interessados no arquivo map.js.  V\u00e1 em frente, abra-o e digite o seguinte:<\/p>\n<div class=\"geshifilter\">\n<div class=\"javascript geshifilter-javascript\" style=\"font-family: monospace;\"><span style=\"color: #003366; font-weight: bold;\">fun\u00e7\u00e3o<\/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;\">se<\/span> <span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">tipo<\/span> <span style=\"color: #339933;\">==<\/span> <span style=\"color: #3366cc;\">\"videira\"<\/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 \/>\nemitir<span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">pontua\u00e7\u00e3o<\/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 nessa fun\u00e7\u00e3o Map, estamos envolvendo tudo em uma instru\u00e7\u00e3o IF.  Essa \u00e9 uma pr\u00e1tica recomendada no Couchbase para verificar os atributos antes de tentar emitir linhas em nosso \u00edndice.  Nesse caso, nossa instru\u00e7\u00e3o IF est\u00e1 garantindo que somente os documentos com o atributo <em>type == \"vine\" (tipo == \"videira\") <\/em>e garantindo que a videira tenha um t\u00edtulo.  A fun\u00e7\u00e3o emit est\u00e1 criando uma linha em nosso \u00edndice usando o documento <strong>Pontua\u00e7\u00e3o<\/strong> como a chave indexada.  Tamb\u00e9m estamos gerando o t\u00edtulo do documento como valor de sa\u00edda.<\/p>\n<p>O motivo pelo qual estamos gerando o <strong>Pontua\u00e7\u00e3o <\/strong>como a chave indexada, \u00e9 que podemos aproveitar a classifica\u00e7\u00e3o Unicode que o Couchbase aplica automaticamente a esse campo.  No nosso caso, precisamos garantir que a pontua\u00e7\u00e3o seja decrescente, para colocar o Vine com a maior pontua\u00e7\u00e3o no topo da tabela de classifica\u00e7\u00e3o.  Essa fun\u00e7\u00e3o de mapa funcionar\u00e1 bem por si s\u00f3 e, se voc\u00ea executar o aplicativo agora, ter\u00e1 uma lista de v\u00eddeos do Vine, mas eles estar\u00e3o na ordem errada!<\/p>\n<p>Chegou a hora de aplicar outro recurso do Couchbase para aprimorar nosso Leaderboard e garantir que ele funcione como deveria.  \u00c9 hora de <strong>Consultar nossa visualiza\u00e7\u00e3o<\/strong> para criar nosso produto final.   Mais uma vez, o Couchbase-Model nos permite fazer isso diretamente do nosso c\u00f3digo Rails.  Abra seu arquivo de modelo <em>\u00a0vine.rb \u00a0<\/em>e adicione a seguinte linha logo acima da declara\u00e7\u00e3o \"private\":<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0visualiza\u00e7\u00e3o <span style=\"color: #ff3333; font-weight: bold;\">:all<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:limite<\/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;\">verdadeiro<\/span><\/div>\n<\/div>\n<p>Esse c\u00f3digo n\u00e3o s\u00f3 \u00e9 necess\u00e1rio para adicionar par\u00e2metros de consulta \u00e0 nossa visualiza\u00e7\u00e3o, mas tamb\u00e9m deve ser adicionado ao nosso arquivo Vine.rb com ou sem par\u00e2metros de consulta para garantir que nosso aplicativo saiba qual(is) visualiza\u00e7\u00e3o(\u00f5es) deve(m) ser usada(s) em nosso aplicativo.  Nesse caso, podemos ver que n\u00e3o s\u00f3 estamos definindo qual visualiza\u00e7\u00e3o nosso aplicativo deve usar, mas tamb\u00e9m adicionamos os par\u00e2metros 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;\">:limite<\/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;\">verdadeiro<\/span><\/div>\n<\/div>\n<p>Ao fazer isso, estamos limitando a sa\u00edda da visualiza\u00e7\u00e3o a 10 resultados e estamos garantindo que o <strong>Pontua\u00e7\u00e3o <\/strong>est\u00e1 em ordem decrescente.<\/p>\n<p>\u00c9 isso a\u00ed!  Se voc\u00ea preencher seu banco de dados com alguns v\u00eddeos do Vine, ver\u00e1 que tem um aplicativo Rate my Vine totalmente funcional.  Ao longo deste artigo, vimos como podemos modelar dados com a gem Couchbase Rails Couchbase-Model do Couchbase, vimos como podemos usar visualiza\u00e7\u00f5es no Couchbase para criar aplicativos interativos e vimos como podemos consultar essas visualiza\u00e7\u00f5es para obter subconjuntos espec\u00edficos de dados para uso em nosso aplicativo.<\/p>\n<p>Sei que nem tudo dentro do aplicativo est\u00e1 neste artigo (estilo etc.), mas isso n\u00e3o \u00e9 importante.  Espero ter abordado os pontos principais (Couchbase-Model, Modelagem de documentos, Visualiza\u00e7\u00f5es e Consultas) o suficiente para que voc\u00ea sinta que pode iniciar seu pr\u00f3prio aplicativo Rails usando a gem Couchbase-Model.<\/p>\n<p>Se voc\u00ea \u00e9 nativo de Londres, n\u00e3o deixe de participar do nosso <a href=\"https:\/\/www.meetup.com\/Couchbase-London\/\">Encontro do Couchbase em Londres<\/a> Nas pr\u00f3ximas semanas, realizaremos eventos sobre Modelagem de documentos, Couchbase Mobile e muitos outros t\u00f3picos.<\/p>\n<p>Se voc\u00ea leu at\u00e9 aqui, s\u00f3 posso parabeniz\u00e1-lo! Sei que este foi um artigo LONGO!  Se voc\u00ea tiver alguma d\u00favida, como sempre, ficarei feliz em respond\u00ea-la.  Entre em contato comigo no Twitter em <em><strong><a href=\"https:\/\/twitter.com\/rbin\">@Rbin<\/a><\/strong><\/em> e me envie qualquer pergunta por l\u00e1!<\/p>\n<p><strong>Robin Johnson<br \/>\nDefensor do desenvolvedor, 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.4 (Yoast SEO v26.4) - 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\/pt\/ruby-rails-and-couchbase-model-social-application\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\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\/pt\/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\":\"pt-BR\",\"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\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\":\"pt-BR\",\"@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\/pt\/author\/jennifer-garcia\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ruby on Rails e Couchbase-Model para um aplicativo social!","description":"Saiba como modelar dados com a gem Couchbase Rails Couchbase-Model e como consultar visualiza\u00e7\u00f5es para obter subconjuntos espec\u00edficos de dados para uso em nosso aplicativo.","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\/pt\/ruby-rails-and-couchbase-model-social-application\/","og_locale":"pt_BR","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\/pt\/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":"pt-BR","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 e Couchbase-Model para um aplicativo 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":"Saiba como modelar dados com a gem Couchbase Rails Couchbase-Model e como consultar visualiza\u00e7\u00f5es para obter subconjuntos espec\u00edficos de dados para uso em nosso aplicativo.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@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":"Blog do Couchbase","description":"Couchbase, o banco de dados 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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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":"A equipe do Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@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 \u00e9 gerente s\u00eanior de Web na Couchbase Inc. Como gerente do site, Jennifer tem a responsabilidade geral pelas propriedades do site, incluindo design, implementa\u00e7\u00e3o, conte\u00fado e desempenho.","sameAs":["https:\/\/www.couchbase.com"],"url":"https:\/\/www.couchbase.com\/blog\/pt\/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 \u00e9 gerente s\u00eanior de Web na Couchbase Inc. Como gerente do site, Jennifer tem a responsabilidade geral pelas propriedades do site, incluindo design, implementa\u00e7\u00e3o, conte\u00fado e desempenho."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1771"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1771\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1771"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}