{"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\/ruby-rails-and-couchbase-model-social-application\/","title":{"rendered":"Ruby on Rails and Couchbase-Model for a Social Application!"},"content":{"rendered":"<h2>Also using HAML, SASS, Bootstrap, And Twitter OmniAuth&#8230;<\/h2>\n<p>Before we start \u2013 <a href=\"https:\/\/github.com\/rbin\/rvine\">Here\u2019s the GitHub code for this App\u2026<\/a><\/p>\n<p>We recently had our 3rd Couchbase San Francisco conference which, by the way, \u00a0was a great success and a fantastic day \/ night. \u00a0At the conference, I gave an 80-minute session based on the very sample application we are going to be building today. \u00a0The purpose of my talk was to show how we can model JSON documents within Couchbase and utilise the full Map\/Reduce capabilities to build an application end-to-end.<\/p>\n<p>This blog assumes knowledge of Rails and some use of the Twitter Developer Portal.\u00a0 If you haven\u2019t used Couchbase or the Couchbase-Model gem before, don\u2019t worry, I will guide you through that part, but it is worth reading up on <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Couchbase-Model<\/a> first!<\/p>\n<p>The overall idea behind this app is that Users can post their own Vine videos, to be voted on by the public to see who has the Funniest Vine videos globally.\u00a0 Users must be authenticated before submitting a Vine, and we need to keep track of which Vine belongs to which user by means of referential ID\u2019s. i.e. each Vine should have a User_ID within it\u2019s JSON document, so we know who it belongs to.<\/p>\n<p>So without further hesitation, let&#8217;s dive in and see how we can build a gamified application atop-of Couchbase using Ruby and Rails. \u00a0The whole idea of having a social application with a leaderboard and a competitive element is one that has been a very common use-case, but not necessarily one that has been well documented (especially for us in the Ruby community!)\u00a0 Now then, enough chit-chat, let\u2019s go!<\/p>\n<h3>Prerequisites:<\/h3>\n<ul>\n<li>Couchbase Server 2.0+<\/li>\n<li>Ruby 1.9.3+<\/li>\n<li>Rails 3+<\/li>\n<\/ul>\n<p>Instead of posting every individual gem for our Rails app here, simply <a href=\"https:\/\/github.com\/rbin\/rvine\/blob\/master\/Gemfile\">click here<\/a> to view my Gemfile to see which Ruby Gems we need to bundle for our application.<\/p>\n<p>1 note to make here is my choice of Ruby server.\u00a0 I am using Puma.\u00a0 This isn\u2019t necessarily a benefit in this small use-case, more a personal habit.\u00a0 Puma is a threaded, concurrent webserver for Ruby that starts on port :9292 by default.\u00a0 You can use whichever web server you feel comfortable with, and simply start your app with \u2018rails s\u2019 or \u2018rails server\u2019.<\/p>\n<p>Now, before we get started with our code, let\u2019s go ahead and create a bucket in our Couchbase instance called \u2018rvine\u2019.\u00a0 It\u2019s not necessary to worry about sizing this bucket, so depending on how much RAM you have allocated to your cluster, just give it 200mb or so.<\/p>\n<p>So, let\u2019s generate a new Rails app.\u00a0 We\u2019re going to append our usual command with the \u2018-O\u2019 flag.\u00a0 This is to skip active_record includes. (We can\u2019t use active_record with Couchbase, but that is why we have the Couchbase-Model gem!)<\/p>\n<p><em>Rails new rvine \u2013O<\/em><\/p>\n<p>Now then,\u00a0 let\u2019s make sure you\u2019ve copied the Gemfile from the repo linked above. \u00a0The importance of this is to make sure we\u2019ve got both Couchbase and <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model\">Couchbase-Model<\/a> bundled.\u00a0 Couchbase-Model is an abstraction over the Couchbase gem allowing Active-Record like design patterns.\u00a0 It makes it super easy for us to get up and running with Rails &amp; Couchbase.\u00a0 Make sure you click on the link above and read through the gem details to find out more.<\/p>\n<p>When we know we have both gems in our Gemfile, run \u2018bundle install.\u2019\u00a0 Once we\u2019ve done that, we setup our rails app with Couchbase as a backend.\u00a0 From your rails directory in Terminal, run the command:<\/p>\n<p><em>Rails generate couchbase:config<\/em><\/p>\n<p>This will generate a couchbase.yml file in our config directory that links up our app with our database backend.\u00a0 \u00a0Go ahead and edit that file, and enter our bucket credentials.\u00a0 Your config file should reflect this:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">common: &amp;common<br \/>\nhostname: localhost<br \/>\nport: 8091<br \/>\nusername:<br \/>\npassword:<br \/>\npool: defaultdevelopment:<br \/>\n&lt;\u00a0 bucket: rvine<\/p>\n<p>test:<br \/>\n&lt;\u00a0 bucket: rvine<\/p>\n<p># set these environment variables on your production server<br \/>\nproduction:<br \/>\nhostname: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_HOST&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\nport: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_PORT&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\nusername: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_USERNAME&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\npassword: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_PASSWORD&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\npool: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_POOL&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> <span style=\"color: #006600; font-weight: bold;\">%&gt;<\/span><br \/>\nbucket: <span style=\"color: #006600; font-weight: bold;\">&lt;%<\/span>= ENV<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;COUCHBASE_BUCKET&#8217;<\/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, so now that that\u2019s done, we should have a Rails barebone project, that\u2019s hooked up to Couchbase as it\u2019s backend data store.\u00a0 Seem simple? That\u2019s because Couchbase-Model makes our life 1000x easier when it comes to data modeling!<\/p>\n<p>Now, the next thing we need to do is setup our <strong><em>User &amp; Authentication classes.<\/em><\/strong><\/p>\n<p>Let\u2019s create our User model first.\u00a0 Create the file \/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;\">class<\/span> User <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">Couchbase::Model<\/span><\/p>\n<p>attribute <span style=\"color: #ff3333; font-weight: bold;\">:name<\/span><br \/>\nattribute <span style=\"color: #ff3333; font-weight: bold;\">:twit_username<\/span><br \/>\nattribute <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;\">self<\/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 \/>\nuser = 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;\">unless<\/span> user<br \/>\nuser = User.<span style=\"color: #9900cc;\">create<\/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;\">:name<\/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;\">:name<\/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;\">:image<\/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;\">end<\/span><br \/>\nuser<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<\/div>\n<\/div>\n<p>The <strong>attributes<\/strong> in this document are the fields we wish to include in our JSON document.\u00a0 We are collecting the user\u2019s Name, Twitter Username &amp; Avatar.\u00a0 We need to give a unique key to each User in our database.\u00a0 In this instance, we are doing so by collecting the User\u2019s twitter UID and creating a hash from that to generate a key for our User document.\u00a0 It\u2019s important to remember that the key of every document in our database must be unique.\u00a0 Also, worth noting is the class we have created. \u2018find_or_create_from_auth_hash\u2019\u00a0 This class is doing exactly what it says on the tin! If a user exists; auth them. If not, create them from the Twitter details we receive.<\/p>\n<p>You will hopefully have noticed that we have chosen to use Twitter-Omniauth for this, to save us a hell of a lot of time instead writing an Auth class from scratch!\u00a0 The first thing to do here, is to head over to Twitter Dev and grab some application keys!\u00a0 If you have never done this before,\u00a0sign in with your Twitter account.\u00a0 Create a new application called \u2018rvine\u2019 and once you\u2019ve done that, you will be presented with 2 application keys.<\/p>\n<p>Create a config file in config\/initializers\/omniauth.rb.\u00a0 Once you have created this file, open it up and drop in the following code:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">Rails.<span style=\"color: #9900cc;\">application<\/span>.<span style=\"color: #9900cc;\">config<\/span>.<span style=\"color: #9900cc;\">middleware<\/span>.<span style=\"color: #9900cc;\">use<\/span> <span style=\"color: #6666ff; font-weight: bold;\">OmniAuth::Builder<\/span> <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nprovider <span style=\"color: #ff3333; font-weight: bold;\">:twitter<\/span>, <span style=\"color: #996600;\">&#8220;CONSUMER_KEY&#8221;<\/span>, <span style=\"color: #996600;\">&#8220;CONSUMER_SECRET&#8221;<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/div>\n<\/div>\n<p>This should now mean we have Omniauth setup with our Twitter application keys, and almost ready to go.\u00a0 The next thing we need to do is create a route in our Rails application to handle the Authentication process.\u00a0 So, let\u2019s open up our config\/routes.rb file, and enter the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">match <span style=\"color: #996600;\">&#8216;\/auth\/twitter\/callback&#8217;<\/span>, <span style=\"color: #ff3333; font-weight: bold;\">:to<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #996600;\">&#8216;sessions#create&#8217;<\/span><\/div>\n<\/div>\n<p>Now, we\u2019re telling Rails to send our Twitter Auth\u2019d callback to our sessions controller\u2026. What sessions controller?\u00a0\u00a0 We need to create that now.<\/p>\n<p>Go ahead and create file 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;\">class<\/span> SessionsController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> ApplicationController<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> create<br \/>\nuser = 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 \/>\nsession<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> = user.<span style=\"color: #9900cc;\">id<\/span><br \/>\nflash<span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #ff3333; font-weight: bold;\">:success<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span> = <span style=\"color: #996600;\">&#8220;Welcome to the club!&#8221;<\/span><br \/>\nredirect_to dashboard_path<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span>protected<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> auth_hash<br \/>\nrequest.<span style=\"color: #9900cc;\">env<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8216;omniauth.auth&#8217;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<\/div>\n<\/div>\n<p>As you can see from this code, our \u2018Create\u2019 method is calling the class we defined in our User.rb to initialize a session when a User clicks to authenticate from the frontend, or create the User if they don\u2019t already exist.\u00a0 Once authenticated, we are redirecting the User to their Dashboard. (Which we will create soon!)<\/p>\n<p>Next up, let\u2019s update our <em>application_controller.rb <\/em>to include a helper classes for our Authentication \u2013 including a helper method to define a Current_User and a helper method to ensure a User is Signed in.<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #9966cc; font-weight: bold;\">class<\/span> ApplicationController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">ActionController::Base<\/span><br \/>\nprotect_from_forgery<span style=\"color: #9966cc; font-weight: bold;\">def<\/span> authenticate!<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">if<\/span> signed_in?<br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">return<\/span> <span style=\"color: #0000ff; font-weight: bold;\">true<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">else<\/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;\">&#8220;You aren&#8217;t authorized to access this page&#8221;<\/span><br \/>\nredirect_to<span style=\"color: #006600; font-weight: bold;\">(<\/span>root_path<span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> current_user<br \/>\n<span style=\"color: #0066ff; font-weight: bold;\">@current_user<\/span> <span style=\"color: #006600; font-weight: bold;\">||<\/span>= User.<span style=\"color: #9900cc;\">find_by_id<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>session<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;\">end<\/span><br \/>\nhelper_method <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;\">end<\/span><br \/>\nhelper_method <span style=\"color: #ff3333; font-weight: bold;\">:signed_in<\/span>?<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<\/div>\n<\/div>\n<p>Next up, we need to create the Dashboard for our Users to be redirected to upon authorisation.\u00a0 For this, let\u2019s use a Rails Generate command.<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">rails generate controller dashboards<\/div>\n<\/div>\n<p>Now, let\u2019s open up the file <em>app\/controllers\/dashboards_controller.rb<\/em> and enter the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\n<p><span style=\"color: #9966cc; font-weight: bold;\">class<\/span> DashboardsController <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> ApplicationController<\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">def<\/span> show<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<\/div>\n<\/div>\n<p>Let\u2019s open up our frontend view of the Dashboard, and edit that. In my case, it\u2019s going to be a HAML file.\u00a0 Regardless of whether you choose ERB or HAML, the file is going to look pretty much the same!\u00a0 In <em>app\/views\/dashboards<\/em> &#8211; just create the file show.haml or 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>section<span style=\"color: #008000; font-style: italic;\">#welcome<\/span><br \/>\n.<span style=\"color: #9900cc;\">page<\/span><span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span>header<br \/>\n<span style=\"color: #006600; font-weight: bold;\">&#8211;<\/span> <span style=\"color: #9966cc; font-weight: bold;\">if<\/span> signed_in?<br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nHello, <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> 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;\">&#8220;Avatar&#8221;<\/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;\">&#8220;All vines&#8221;<\/span>, <span style=\"color: #996600;\">&#8220;\/vines&#8221;<\/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;\">else<\/span><br \/>\n<span style=\"color: #006600; font-weight: bold;\">%<\/span>h1<br \/>\nHello, stranger<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;\">&#8220;Sign in with your twitter account&#8221;<\/span>, <span style=\"color: #996600;\">&#8220;\/auth\/twitter&#8221;<\/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>Now we\u2019ve got our dashboard in place, we need to setup some more Routing, then we can go ahead and test things!\u00a0 Open up <em>config\/routes.rb <\/em>and add the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">resource <span style=\"color: #ff3333; font-weight: bold;\">:dashboard<\/span><\/div>\n<\/div>\n<p>Once you\u2019ve done that, save, run your app, and Authenticate as a user.<\/p>\n<p>Great! We can now see that our Authentication works, and our Users have a Dashboard.\u00a0 If we open up our Couchbase console, we should also see that a User has been created inside our Rvine bucket!<\/p>\n<p>Now we\u2019ve got our Users and Authentication in place, let\u2019s get onto the main part of the application: The Vine Videos!\u00a0 To get started here, we\u2019re going to need to create a model for Vines.\u00a0 Now, unfortunately, Couchbase-Model does not yet support the rails Generator on this action.\u00a0 So we need to manually create\u00a0 <em>\/app\/models\/vine.rb<\/em><\/p>\n<p>Once we\u2019ve done that, let\u2019s fill in the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\"><span style=\"color: #cc0066; font-weight: bold;\">require<\/span> <span style=\"color: #996600;\">&#8216;open-uri&#8217;<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">require<\/span> <span style=\"color: #996600;\">&#8216;uri&#8217;<\/span><br \/>\n<span style=\"color: #cc0066; font-weight: bold;\">require<\/span> <span style=\"color: #996600;\">&#8216;nokogiri&#8217;<\/span><span style=\"color: #9966cc; font-weight: bold;\">class<\/span> Vine <span style=\"color: #006600; font-weight: bold;\">&lt;<\/span> <span style=\"color: #6666ff; font-weight: bold;\">Couchbase::Model<\/span><br \/>\nafter_save <span style=\"color: #ff3333; font-weight: bold;\">:extract_video_url<\/span><\/p>\n<p>belongs_to <span style=\"color: #ff3333; font-weight: bold;\">:user<\/span><\/p>\n<p>attribute <span style=\"color: #ff3333; font-weight: bold;\">:title<\/span><br \/>\nattribute <span style=\"color: #ff3333; font-weight: bold;\">:vine_url<\/span><br \/>\nattribute <span style=\"color: #ff3333; font-weight: bold;\">:video_url<\/span><\/p>\n<p><span style=\"color: #008000; font-style: italic;\">#Voting API<\/span><br \/>\nattribute <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>private<\/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;\">open<\/span><span style=\"color: #006600; font-weight: bold;\">(<\/span>vine_url<span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">read<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span><br \/>\n<span style=\"color: #0000ff; font-weight: bold;\">self<\/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;\">&#8220;source&#8221;<\/span><span style=\"color: #006600; font-weight: bold;\">)<\/span>.<span style=\"color: #9900cc;\">first<\/span><span style=\"color: #006600; font-weight: bold;\">[<\/span><span style=\"color: #996600;\">&#8220;src&#8221;<\/span><span style=\"color: #006600; font-weight: bold;\">]<\/span><br \/>\nsave_without_callbacks<br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<p><span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/p>\n<\/div>\n<\/div>\n<p>As we can see from the code above, we are including open-uri, uri, and nokogiri.\u00a0 This is because Vine does not have a public API, but we need to get those videos somehow!\u00a0\u00a0 So, with the help of those libraries we\u2019ve written a cheeky script to scrape the source of a Vine video and grab the exact mp4 URI when a User enters the Vine URL.<\/p>\n<p>The class <em>extract_video_url<\/em> is called using the method <em>after_save<\/em>.\u00a0 From the code we can see Nokogiri is opening the URL entered by our User on posting a Vine.\u00a0 It then searches the Vine page\u2019s source to find the line declaring the Vine\u2019s actual mp4 URI.<\/p>\n<p>Other than that, we can see that each Vine belongs to a User, has attributes for the Title, Vine URL (Entered by the user) and Video URL (Actual mp4 URI).\u00a0 We also have a Score attribute. (<strong>The most important attribute.) <\/strong>Also note that we are setting each video to start with a score of 1.<\/p>\n<p>Now, let\u2019s generate a controller &amp; views for our Vine model. Run:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">rails generate scaffold vines<\/div>\n<\/div>\n<p>You may get a conflict error at this point saying the model already exists. Don\u2019t worry, just say \u2018N\u2019 to not overwrite it.\u00a0 You may also see an error Couchbase not found.\u00a0 Again, don\u2019t worry about this, as I stated above Couchbase-Model isn\u2019t compatible with the Rails Model generator.<\/p>\n<p>If all went to plan, you should now have a <em>vines_controller.rb <\/em>and a whole views folder for vines with the frontend HAML or ERB files.\u00a0 Go ahead and open up <em>vines_controller.rb <\/em>and make sure it reflects the <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/controllers\/vines_controller.rb\">file here<\/a>.<\/p>\n<p>In our controller file, you may have noticed a method called <em>\u2018upvote\u2019. <\/em>\u00a0This is the voting mechanism for our Vine videos.\u00a0 The finish the implementation of this voting system, and to actually give the Vine videos a place to live, open up the file <em>app\/views\/vines\/show.haml(or .erb)<\/em><\/p>\n<p>Make sure it relfects the file <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/show.html.haml\" target=\"_blank\" rel=\"noopener\">found here<\/a>&#8230;<\/p>\n<p>Before our voting system will work completely, we need to add the following to our <em>routes.rb <\/em>file<em>:<\/em><\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0 resources <span style=\"color: #ff3333; font-weight: bold;\">:vines<\/span> <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nmember <span style=\"color: #9966cc; font-weight: bold;\">do<\/span><br \/>\nput <span style=\"color: #ff3333; font-weight: bold;\">:upvote<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><br \/>\n<span style=\"color: #9966cc; font-weight: bold;\">end<\/span><\/div>\n<\/div>\n<p>Ok, so now our Vine videos can be displayed, and the voting mechanism is in place!\u00a0 The next thing we need to do is setup the main page for the app \u2013 <strong>The Leaderboard!<\/strong>\u00a0 Our leaderboard, although being the main feature of the app, is incredibly simple.\u00a0 Open up the file\u00a0 <em>app\/views\/vines\/index.haml (or .erb)\u00a0 <\/em>and ensure it matches the <a href=\"https:\/\/raw.github.com\/rbin\/rvine\/master\/app\/views\/vines\/index.html.haml\">code here<\/a>.<\/p>\n<p>Now, if this were any ordinary relational Rails app, we <strong>should<\/strong> in theory have a leaderboard already created, listing each Vine video in our database.\u00a0 <strong>BUT<\/strong> this isn\u2019t the case here.<\/p>\n<p>In Couchbase, we need to create our leaderboard using <strong>Views<\/strong> in Couchbase and utilising the Map\/Reduce technique before we get a leaderboard that actually works properly!\u00a0 So, let\u2019s do that!\u00a0 Before we proceed here, if you haven\u2019t used Couchbase Views prior to this, I recommend you read <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/3.x\/admin\/Views\/views-intro.html\">these docs<\/a>, to give you a good bit of background knowledge on what Couchbase Views are, how we use them and to ease your way into using them in this Rails application.<\/p>\n<p>For our application, we need to create a View in Couchbase, that outputs each vine, with it\u2019s Score and Title.\u00a0 They also need to be ordered, descending, by Score so the Vine video with the highest score is naturally at the top of the Leaderboard.<\/p>\n<p>IF you have used Couchbase Views before, you may have created them from within the Admin console itself.\u00a0 Views can be created from within the Admin UI, from any of our SDK clients and by means of the REST API.\u00a0 In this case, Couchbase-Model has a unique, and rather brilliant way of allowing us to generate Views for our application. Have a quick read of <a href=\"https:\/\/github.com\/avsej\/ruby-couchbase-model#views-aka-mapreduce-indexes\">these docs<\/a> to see how it can be done, and how we\u2019re about to do it.<\/p>\n<p>In Terminal, simply run:<\/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>Now, in your\u00a0 <em>app\/models <\/em>directory, you should have a new sub-directory named vine, with a subdirectory named all.\u00a0 This directory contains 2 .js files \u2013 our map.js and reduce.js.\u00a0 For now, all we\u2019re interested in the map.js file.\u00a0 Go ahead and open it up, and enter the following:<\/p>\n<div class=\"geshifilter\">\n<div class=\"javascript geshifilter-javascript\" style=\"font-family: monospace;\"><span style=\"color: #003366; font-weight: bold;\">function<\/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;\">if<\/span> <span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">type<\/span> <span style=\"color: #339933;\">==<\/span> <span style=\"color: #3366cc;\">&#8220;vine&#8221;<\/span> <span style=\"color: #339933;\">&amp;&amp;<\/span> doc.<span style=\"color: #660066;\">title<\/span><span style=\"color: #009900;\">)<\/span> <span style=\"color: #009900;\">{<\/span><br \/>\nemit<span style=\"color: #009900;\">(<\/span>doc.<span style=\"color: #660066;\">score<\/span><span style=\"color: #339933;\">,<\/span> doc.<span style=\"color: #660066;\">title<\/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>As we can see from this Map function; we are wrapping the entire thing in an IF statement.\u00a0 This is a best practice within Couchbase to check for attributes before trying to emit rows into our Index.\u00a0 In this case, our IF statement is ensuring only docs with the <em>type == \u201cvine\u201d <\/em>and ensuring the vine has a title.\u00a0 The emit function is then creating a row in our index using the document <strong>Score<\/strong> as the indexed key.\u00a0 We are also outputting the document Title as the output value.<\/p>\n<p>The reason we are outputting the <strong>Score <\/strong>as the Indexed key, is that we can take advantage of the Unicode Sorting that Couchbase automatically applies to this field.\u00a0 In our case, we need to ensure our Score\u2019s are descending, to push the highest scoring Vine to the top of the Leaderboard.\u00a0 This map function will work fine on it\u2019s own, and if you ran the application now, you will have a list of Vine videos, but they would be in the wrong order!<\/p>\n<p>It\u2019s time to apply another feature of Couchbase to polish off our Leaderboard and ensure it works as it should.\u00a0 It\u2019s time to <strong>Query our View<\/strong> to create our final product.\u00a0\u00a0 Once again, Couchbase-Model allows us to do this straight from our Rails code.\u00a0 Open up your model file <em>\u00a0vine.rb \u00a0<\/em>and add the following line just above the \u2018private\u2019 declaration:<\/p>\n<div class=\"geshifilter\">\n<div class=\"ruby geshifilter-ruby\" style=\"font-family: monospace;\">\u00a0view <span style=\"color: #ff3333; font-weight: bold;\">:all<\/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;\">:descending<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #0000ff; font-weight: bold;\">true<\/span><\/div>\n<\/div>\n<p>Not only is this code necessary to add query params to our View, but it must be added to our Vine.rb file with or without query parameters to ensure our application knows which View(s) it has to use in our application.\u00a0 In this case, we can see, not only are we defining which view our application is to use, but we have also added the query parameters:<\/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;\">:descending<\/span> <span style=\"color: #006600; font-weight: bold;\">=&gt;<\/span> <span style=\"color: #0000ff; font-weight: bold;\">true<\/span><\/div>\n<\/div>\n<p>By doing so, we are limiting the View\u2019s output to 10 results and we are ensuring the <strong>Score <\/strong>is in descending order.<\/p>\n<p>That\u2019s it!\u00a0 If you populate your database with a few Vine videos, you should see you have a fully working Rate my Vine application.\u00a0 Throughout this article we have seen how we can model data with the Couchbase Rails gem Couchbase-Model, we have seen how we can use Views in Couchbase to create interactive applications, and we have seen how we can Query on those Views to get specific subsets of data for use in our application.<\/p>\n<p>I realise that not everything inside the app is in this article (styling etc.) but that is unimportant.\u00a0 I hope I have covered the main points (Couchbase-Model, Document Modelling, Views and Queries) well enough so that you feel you could start your own Rails app using the Couchbase-Model gem.<\/p>\n<p>If you are a London native, make sure you join our <a href=\"https:\/\/www.meetup.com\/Couchbase-London\/\">Couchbase London Meetup<\/a> as over the coming weeks we will be hosting events detailing Document Modelling, Couchbase Mobile and many other topics.<\/p>\n<p>If you have read this far, I can only congratulate you! I know this has been a LONG article!\u00a0 If you have any questions, as always, I am happy to answer them.\u00a0 Hit me up on Twitter at <em><strong><a href=\"https:\/\/twitter.com\/rbin\">@Rbin<\/a><\/strong><\/em> and ping me any questions on there!<\/p>\n<p><strong>Robin Johnson<br \/>\nDeveloper Advocate, Europe.<\/strong><\/p>\n","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>\n","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 v25.7.1 (Yoast SEO v25.7) - 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\/ruby-rails-and-couchbase-model-social-application\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\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\/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 minutes\" \/>\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\":\"en-US\",\"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\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@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\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@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\":\"en-US\",\"@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\/author\/jennifer-garcia\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ruby on Rails and Couchbase-Model for a Social Application!","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.","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\/ruby-rails-and-couchbase-model-social-application\/","og_locale":"en_US","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\/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 minutes"},"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":"en-US","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":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/ruby-rails-and-couchbase-model-social-application\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@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":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@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":"en-US","@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\/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 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."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=1771"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1771\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=1771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=1771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=1771"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}