Статьи

Ruby on Rails и Couchbase-модель для социального приложения

Этот пост был изначально написан Робин Джонсон

Также используя HAML, SASS, Bootstrap и Twitter OmniAuth …

Прежде чем мы начнем — вот код GitHub для этого приложения …

Недавно мы провели третью конференцию Couchbase в Сан-Франциско, которая, кстати, имела большой успех и фантастический день / ночь. На конференции я дал 80-минутную сессию на основе того самого примера приложения, которое мы собираемся создать сегодня. Цель моего выступления состояла в том, чтобы показать, как мы можем моделировать документы JSON в Couchbase и использовать все возможности Map / Reduce для создания комплексного приложения.

Этот блог предполагает знание Rails и некоторое использование портала разработчиков Twitter. Если вы раньше не использовали Couchbase или гем Couchbase-Model, не беспокойтесь, я проведу вас через эту часть, но сначала стоит прочитать о Couchbase-Model !

Общая идея этого приложения заключается в том, что пользователи могут публиковать свои собственные видео Vine, чтобы за них проголосовала публика, чтобы увидеть, кто имеет самые смешные видео Vine во всем мире. Пользователи должны пройти проверку подлинности перед отправкой Vine, и мы должны отслеживать, кому принадлежит Vine, с помощью ссылочных идентификаторов. т.е. каждый Vine должен иметь User_ID в своем документе JSON, поэтому мы знаем, кому он принадлежит.

Поэтому, не задумываясь, давайте окунемся и посмотрим, как мы можем создать игровое приложение поверх Couchbase, используя Ruby и Rails. В целом идея иметь социальное приложение с таблицей лидеров и конкурентным элементом является той, которая была очень распространенным вариантом использования, но не обязательно той, которая была хорошо документирована (особенно для нас в сообществе Ruby!). Теперь тогда достаточно болтовня, пошли!

Предпосылки:

  • Couchbase Server 2.0+
  • Ruby 1.9.3+
  • Рельсы 3+

Вместо того, чтобы публиковать здесь каждый отдельный гем для нашего приложения Rails, просто нажмите здесь, чтобы посмотреть мой Gemfile, чтобы увидеть, какие Ruby Gems нам нужно связать для нашего приложения.

1 примечание, чтобы сделать это мой выбор сервера Ruby. Я использую Puma. Это не обязательно выгода в этом маленьком случае использования, скорее личная привычка. Puma — это параллельный многопоточный веб-сервер для Ruby, который по умолчанию запускается через порт: 9292. Вы можете использовать любой веб-сервер, с которым вам удобно, и просто запустить свое приложение с помощью «rails s» или «rails server».

Теперь, прежде чем мы начнем с нашим кодом, давайте продолжим и создадим сегмент в нашем экземпляре Couchbase под названием ‘rvine’. Не нужно беспокоиться о размере этого сегмента, поэтому в зависимости от того, сколько ОЗУ выделено для вашего кластера, просто дайте ему 200 МБ или около того.

Итак, давайте создадим новое приложение Rails. Мы собираемся добавить нашу обычную команду с флагом ‘-O’. Это пропустить включает active_record. (Мы не можем использовать active_record с Couchbase, но именно поэтому у нас есть гем Couchbase-Model!)

Рельсы нового рва –O

Теперь давайте удостоверимся, что вы скопировали Gemfile из репозитория, указанного выше. Важность этого заключается в том, чтобы убедиться, что у нас есть и Couchbase, и Couchbase-Model . Couchbase-Model — это абстракция над самоцветом Couchbase, позволяющая использовать Active-Record как шаблоны проектирования. Это позволяет нам легко начать работу с Rails & Couchbase. Убедитесь, что вы нажали на ссылку выше и прочитали детали драгоценного камня, чтобы узнать больше.

Когда мы узнаем, что в нашем Gemfile есть оба камня, запустите «bundle install». Как только мы это сделаем, мы настроим наше приложение rails с Couchbase в качестве бэкэнда. Из вашей директории rails в Terminal запустите команду:

Rails генерирует couchbase: config

Это создаст файл couchbase.yml в нашей директории config, который связывает наше приложение с нашей базой данных. Идите вперед и отредактируйте этот файл и введите наши учетные данные. Ваш конфигурационный файл должен отражать это:

common: &common
  hostname: localhost
  port: 8091
  username:
  password:
  pool: default

development:
  <<: *common
  bucket: rvine

test:
  <<: *common
  bucket: rvine

# set these environment variables on your production server
production:
  hostname: <%= ENV['COUCHBASE_HOST'] %>
  port: <%= ENV['COUCHBASE_PORT'] %>
  username: <%= ENV['COUCHBASE_USERNAME'] %>
  password: <%= ENV['COUCHBASE_PASSWORD'] %>
  pool: <%= ENV['COUCHBASE_POOL'] %>
  bucket: <%= ENV['COUCHBASE_BUCKET'] %>

Итак, теперь, когда все готово, у нас должен быть голый Rails-проект, который подключается к Couchbase в качестве внутреннего хранилища данных. Кажется простым? Это потому что Couchbase-Model делает нашу жизнь в 1000 раз проще, когда дело доходит до моделирования данных!

Теперь, следующее, что нам нужно сделать, это настроить наши классы User & Authentication.

Давайте сначала создадим нашу модель User. Создайте файл /app/models/user.rb

class User < Couchbase::Model

  attribute :name
  attribute :twit_username
  attribute :avatar

  def self.find_or_create_from_auth_hash(hash)
    user = User.find_by_id(hash[:uid])
    unless user
      user = User.create!(:id => hash[:uid],
                          :name => hash[:info][:name],
                          :twit_username => hash[:info][:nickname],
                          :avatar => hash[:info][:image])
    end
    user
  end
end

Эти атрибуты в этом документе , являются полями , которые мы хотим включить в нашем JSON документе. Мы собираем имя пользователя, имя пользователя в Twitter и аватар. Нам нужно дать уникальный ключ каждому пользователю в нашей базе данных. В этом случае мы собираем UID пользователя в твиттере и создаем из него хеш, чтобы сгенерировать ключ для нашего пользовательского документа. Важно помнить, что ключ каждого документа в нашей базе данных должен быть уникальным. Также стоит отметить класс, который мы создали. ‘find_or_create_from_auth_hash’ Этот класс делает именно то, что говорит на жестяной коробке! Если пользователь существует; Аут их. Если нет, создайте их из деталей Twitter, которые мы получаем.

Мы надеемся, что вы заметили, что мы решили использовать Twitter-Omniauth для этого, чтобы сэкономить нам массу времени вместо написания класса Auth с нуля! Первое, что нужно сделать здесь, это зайти в Twitter Dev и взять несколько ключей приложения! Если вы никогда не делали этого раньше, нажмите здесь и войдите в свою учетную запись Twitter. Создайте новое приложение под названием «rvine», и после того, как вы это сделаете, вам будут представлены 2 ключа приложения.

Создайте файл конфигурации в config / initializers / omniauth.rb. Создав этот файл, откройте его и вставьте следующий код:

Rails.application.config.middleware.use OmniAuth::Builder do
    provider :twitter, "CONSUMER_KEY", "CONSUMER_SECRET"
end

Теперь это должно означать, что мы установили Omniauth с нашими ключами приложения Twitter и почти готовы к работе. Следующее, что нам нужно сделать, это создать маршрут в нашем приложении Rails для обработки процесса аутентификации. Итак, давайте откроем наш файл config / rout.rb и введем следующее:

match '/auth/twitter/callback', :to => 'sessions#create'

Теперь мы говорим Rails, чтобы мы отправили наш обратный вызов Twitter Auth’d нашему контроллеру сессий … Какой сеанс контроллера? Нам нужно создать это сейчас. 

Идем дальше и создаем файл app / controllers / session_controller.rb

class SessionsController < ApplicationController
  def create
    user = User.find_or_create_from_auth_hash(auth_hash)
    session[:user_id] = user.id
    flash[:success] = "Welcome to the club!"
    redirect_to dashboard_path
  end

  protected
  def auth_hash
    request.env['omniauth.auth']
  end
end

Как вы можете видеть из этого кода, наш метод Create вызывает класс, который мы определили в нашем User.rb, чтобы инициализировать сеанс, когда пользователь нажимает для аутентификации из внешнего интерфейса, или создавать пользователя, если они еще не существуют. После проверки подлинности мы перенаправляем пользователя на его панель инструментов. (Который мы скоро создадим!)

Далее, давайте обновим наш application_controller.rb, чтобы включить вспомогательные классы для нашей Аутентификации, включая вспомогательный метод для определения Current_User и вспомогательный метод для обеспечения входа пользователя.

class ApplicationController < ActionController::Base
  protect_from_forgery

  def authenticate!
    if signed_in?
      return true
    else
      flash[:error] = "You aren't authorized to access this page"
      redirect_to(root_path)
    end
  end

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end
  helper_method :current_user

  def signed_in?
    !!current_user
  end
  helper_method :signed_in?
end

Далее, нам нужно создать панель инструментов для наших пользователей, на которую будут перенаправляться после авторизации. Для этого воспользуемся командой Rails Generate.

rails generate controller dashboards

Теперь давайте откроем файл app / controllers / dashboards_controller.rb и введем следующее:

class DashboardsController < ApplicationController

  def show
  end

end

Давайте откроем наш внешний вид Dashboard и отредактируем его. В моем случае это будет файл HAML. Независимо от того, выберете ли вы ERB или HAML, файл будет выглядеть примерно одинаково! В app / views / dashboards — просто создайте файл show.haml или show.erb.

%section#welcome
  .page-header
    - if signed_in?
      %h1
        Hello, #{current_user.name}
      %p
        %img{:src => current_user.avatar, :alt => "Avatar"}
      %p= link_to("All vines", "/vines")
    - else
      %h1
        Hello, stranger
      %p
        = link_to("Sign in with your twitter account", "/auth/twitter")
    %p
       

Теперь у нас есть панель инструментов, нам нужно настроить еще одну маршрутизацию, и тогда мы сможем проверить ее! Откройте файл config / rout.rb и добавьте следующее:

resource :dashboard

Как только вы это сделаете, сохраните, запустите ваше приложение и авторизуйтесь как пользователь, и вы должны увидеть что-то вроде следующего:

Большой! Теперь мы можем видеть, что наша Аутентификация работает, и у наших Пользователей есть Панель инструментов. Если мы откроем нашу консоль Couchbase, мы также должны увидеть, что пользователь был создан внутри нашей корзины Rvine!

Теперь у нас есть пользователи и аутентификация, давайте перейдем к основной части приложения: The Vine Videos! Чтобы начать здесь, нам нужно создать модель для Vines. Сейчас, к сожалению, Couchbase-Model пока не поддерживает генератор рельсов в этом действии. Поэтому нам нужно вручную создать  /app/models/vine.rb

Как только мы это сделаем, давайте заполним следующее:

require 'open-uri'
require 'uri'
require 'nokogiri'

class Vine < Couchbase::Model
  after_save :extract_video_url

  belongs_to :user

  attribute :title
  attribute :vine_url
  attribute :video_url

  #Voting API
  attribute :score, :default => 1

  validates_presence_of :title, :vine_url

  private

  def extract_video_url
    doc = Nokogiri(open(vine_url).read)
    self.video_url = doc.css("source").first["src"]
    save_without_callbacks
  end

end

Как видно из приведенного выше кода, мы включаем open-uri, uri и nokogiri. Это потому, что у Vine нет публичного API, но нам нужно как-то получить эти видео! Итак, с помощью этих библиотек мы написали дерзкий сценарий для очистки источника видео Vine и получения точного mp4 URI, когда пользователь вводит URL Vine.

Класс extract_video_url вызывается с использованием метода after_save . Из кода, который мы видим, Nokogiri открывает URL-адрес, введенный нашим пользователем при публикации Vine. Затем он ищет источник на странице Vine, чтобы найти строку, объявляющую фактический mp4 URI Vine.

Кроме этого, мы можем видеть, что каждая Vine принадлежит пользователю, имеет атрибуты для заголовка, Vine URL (введенного пользователем) и Video URL (Actual mp4 URI). У нас также есть атрибут Score. ( Самый важный атрибут.) Также обратите внимание, что мы устанавливаем каждое видео для начала со счетом 1.

Теперь давайте сгенерируем контроллер и представления для нашей модели Vine. Бег:

rails generate scaffold vines

В этот момент вы можете получить сообщение об ошибке, заявив, что модель уже существует. Не волнуйтесь, просто скажите «N», чтобы не перезаписывать его. Вы также можете увидеть ошибку Couchbase не найдена. Опять же, не беспокойтесь об этом, как я уже говорил выше, Couchbase-Model не совместима с генератором Rails Model.

Если все пошло по плану, теперь у вас должен быть vines_controller.rb и целая папка views для лоз с внешними файлами HAML или ERB. Откройте файл vines_controller.rb и убедитесь, что он отражает файл здесь .

В нашем файле контроллера вы, возможно, заметили метод под названием «upvote».  Это механизм голосования для наших видео Vine. Завершите внедрение этой системы голосования и фактически предоставьте видео Vine место для жизни, откройте файл app / views / vines / show.haml (или .erb).

Убедитесь, что он исправляет найденный здесь файл

Прежде чем наша система голосования заработает полностью, нам нужно добавить следующее в наш файл rout.rb :

resources :vines do
    member do
      put :upvote
    end
  end

Итак, теперь наши видео Vine могут быть отображены, и механизм голосования на месте! Следующее, что нам нужно сделать, это настроить главную страницу приложения — Leaderboard!   Наша таблица лидеров, хотя и является основной функцией приложения, невероятно проста. Откройте файл  app / views / vines / index.haml (или .erb)  и убедитесь, что он соответствует коду здесь .

Теперь, если бы это было обычное реляционное приложение на Rails, теоретически у нас уже должна быть таблица лидеров, в которой каждое видео Vine занесено в нашу базу данных.  НО это не тот случай.

В Couchbase нам нужно создать нашу таблицу лидеров, используя Views в Couchbase и используя технику Map / Reduce, прежде чем мы получим таблицу лидеров, которая действительно работает правильно! Итак, давайте сделаем это! Прежде чем мы продолжим здесь, если вы до этого не использовали Couchbase Views, я рекомендую вам прочитать эти документы , чтобы дать вам базовые знания о том, что такое Couchbase Views, как мы их используем и чтобы облегчить вам использование их в этом приложении Rails

Для нашего приложения нам нужно создать представление в Couchbase, которое выводит каждую лозу с ее счетом и заголовком. Их также нужно упорядочить по убыванию по счету, чтобы видео Vine с наивысшим результатом находилось в верхней части таблицы лидеров.

Если вы уже использовали Couchbase Views, возможно, вы создали их из самой консоли администратора. Представления могут быть созданы из пользовательского интерфейса администратора, с любого из наших клиентов SDK и с помощью REST API. В этом случае Couchbase-Model обладает уникальным и довольно блестящим способом, позволяющим нам создавать представления для нашего приложения. Быстро прочитайте эти документы, чтобы увидеть, как это можно сделать, и как мы собираемся это сделать.

В терминале просто запустите:

rails generate couchbase:view vine all

Теперь в вашем каталоге  app / models у вас должен быть новый подкаталог с именем vine, а подкаталог — all. Этот каталог содержит 2 файла .js — наши map.js и redu.js. На данный момент все мы заинтересованы в файле map.js. Идите вперед, откройте его и введите следующее:

function(doc, meta) {
  if (doc.type == "vine" && doc.title) {
    emit(doc.score, doc.title);
  }
}

Как мы видим из этой функции Map; мы оборачиваем все это в оператор IF. В Couchbase рекомендуется проверять атрибуты, прежде чем пытаться выдавать строки в наш индекс. В этом случае наше утверждение IF обеспечивает только документы с типом == «vine» и гарантирует, что лоза имеет заголовок. Затем функция emit создает строку в нашем индексе, используя документ Score в качестве индексированного ключа. Мы также выводим заголовок документа в качестве выходного значения.

Причина, по которой мы выводим Score в качестве индексированного ключа, заключается в том, что мы можем использовать сортировку Unicode, которую Couchbase автоматически применяет к этому полю. В нашем случае, мы должны убедиться, что наш счет снижается, чтобы переместить лозу с наибольшим количеством очков на вершину таблицы лидеров. Эта функция карты будет работать сама по себе, и если вы запустили приложение сейчас, у вас будет список видео Vine, но они будут в неправильном порядке!

Пришло время применить еще одну функцию Couchbase, чтобы отшлифовать нашу таблицу лидеров и убедиться, что она работает как надо. Пришло время запросить наш вид, чтобы создать наш конечный продукт. Еще раз, Couchbase-Model позволяет нам делать это прямо из нашего кода Rails. Откройте файл модели  vine.rb   и добавьте следующую строку чуть выше объявления private:

 view :all, :limit => 10, :descending => true

Этот код необходим не только для добавления параметров запроса в наше представление, но и для добавления в наш файл Vine.rb с параметрами запроса или без него, чтобы наше приложение знало, какие представления необходимо использовать в нашем приложении. В этом случае, мы можем видеть, мы не только определяем, какое представление должно использовать наше приложение, но мы также добавили параметры запроса:

 :limit => 10, :descending => true

Тем самым мы ограничиваем вывод в представлении 10 результатами и гарантируем, что счет будет в порядке убывания. Без особой заботы о стиле, у нас должно быть что-то похожее на это:

Это оно! Если вы заполните свою базу данных несколькими видео Vine, вы должны увидеть, что у вас есть полностью работающее приложение Rate my Vine. В этой статье мы видели, как мы можем моделировать данные с помощью Couchbase-Model из Couchbase Rails, мы видели, как мы можем использовать Views в Couchbase для создания интерактивных приложений, и мы видели, как мы можем запрашивать эти Views для получения определенных подмножеств. данных для использования в нашем приложении.

Я понимаю, что не все внутри приложения находится в этой статье (стиль и т. Д.), Но это неважно. Надеюсь, я достаточно хорошо рассмотрел основные моменты (Couchbase-Model, Document Modeling, Views и Queries), чтобы вы чувствовали, что можете запустить свое собственное приложение Rails, используя гем Couchbase-Model.

Если вы уроженец Лондона, не забудьте присоединиться к нашей конференции Couchbase London Meetup, поскольку в ближайшие недели мы будем проводить мероприятия, посвященные моделированию документов, Couchbase Mobile и многим другим темам.

Если вы прочитали это далеко, я могу только поздравить вас! Я знаю, что это была длинная статья! Если у вас есть какие-либо вопросы, как всегда, я с удовольствием на них отвечу. Напишите мне в Твиттере на @Rbin и задайте мне любые вопросы!