Простейшая free-lance доска на Ruby on Rails

в 20:45, , рубрики: mongoid, ruby on rails, метки: ,

Я исхожу из того, что вы уже минимально знакомы с RoR и что-то пытались на нем делать. Этот материал будет интересен простейшей аутентификацией пользователя посредством OpenID, а также тем, кто давно хотел попробовать MongoDB, но не знал с чего начать.

Мы будем использовать:

  • Ruby on Rails 3.2.8
  • Slim
  • Mongoid
  • Loginza

Создание проекта


rails new lancemine -O -G -T

-O отказываемся от использования ActiveRecord (Mongoid вместо него)
-G отказываемся от гит (я использую Mercurial)
-T отказываемся от тестов

Правим Gemfile, приводя его к такому виду:

source 'https://rubygems.org'

gem 'rails', '3.2.8'

gem 'inherited_resources'
gem 'slim-rails'
gem 'mongoid'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'therubyrhino', :platforms => :mswin
  gem 'therubyracer', :platforms => :ruby
  gem 'execjs'
  gem 'uglifier', '>= 1.0.3'
end
gem 'jquery-rails'

Тут мы добавляем необходимые нам гемы и указываем библиотеки для компиляции JS в зависимости от платформы. therubyracer считается быстрее, но есть проблемы с его компиляцией под win, поэтому мы используем движок Мозиллы.

bundle

Генерируем конфиг для MongoDB
rails g mongoid:config

Mercurial

Если вы хотите использовать систему контроля версий, то я рекомендую Mercurial. На мой взгляд она делает все тоже, что и Git, только проще и логичнее.

Нам понадобиться создать в корне файл .hgignore, чтобы исключить из-под контроля временные и часто изменяющиеся файлы:

db/schema.rb
config/mongoid.yml
.bundle
tmp
Gemfile.lock

syntax: glob

db/*.sqlite3
log/*.log
public/uploads/*
public/assets/*
*.swp
*.orig
*~

Затем выполнить команды:

hg init
hg ci -Am "Init"

-A добавляет все новые файлы под контроль
-m что комментарий к коммиту передается в командной строке.

Модель пользователя

rails g model User openid_identity openid_data:hash status

Это создаст нам модель app/models/user.rb, приведем ее к виду:

class User
  include Mongoid::Document
  include Mongoid::Timestamps
  field :openid_identity, type: String
  field :openid_data, type: Hash
  field :status, type: String
  has_many :projects
end

include Mongoid::Timestamps добавляет привычные нам из AR created_at и updated_at

Проекты

rails g scaffod Project title body budget time

К модели добавим строчки:

include Mongoid::Timestamps
belongs_to :user

Также я внес изменения во вьюхи, их можно будет посмотреть в репозитарии.

Сессии

Регистрации как таковой у нас не будет, вход только через OpenID через Loginza. Для этого мы подключим скрипт по адресу loginza.ru/js/widget.js.

app/views/layouts/application.html.slim:

doctype html
html
  head
    title Lancemine
    = stylesheet_link_tag    "application", :media => "all"
    = javascript_include_tag "application"
    script src="http://loginza.ru/js/widget.js" type="text/javascript"

А для вызова виджета будем использовать вот такую ссылку:
https://loginza.ru/api/widget?token_url=#{u 'http://localhost:3000/signin'}&providers_set=vkontakte,facebook,livejournal

localhost:3000/signin — это адрес куда логинза перенаправит пользователя после входа
providers_set — список разрешенных провайдеров для входа.

Контроллер для обработки:
rails g controller sessions:

class SessionsController < ApplicationController
  require 'net/http'
  require 'json'

  def create
    openid_data = params[:token]
    openid_data = Net::HTTP.get(URI.parse("http://loginza.ru/api/authinfo?token=#{params[:token]}"))
    openid_data = JSON.parse openid_data
    user = User.find_or_create_by(openid_identity: openid_data['identity'])
    if user.status != 'banned'
      user.openid_data = openid_data
      user.save
      session[:user_id] = user.id
      redirect_to root_url, :notice => "Logged in!"
    else
      redirect_to root_url, :notice => "You blocked!"
    end
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_url, :notice => "Logged out!"
  end
end

Здесь мы с помощью библиотеки net/http запрашиваем данные о пользователе с помощь токена, который нам передала Loginza POST запросом на /signin. TODO: необходимо сделать обработку ошибок (Loginza может вернуть ошибку, а тут это не учтено).

Затем пользователь с соответствующим OpenID находится в базе или создается новый, а в сессию записывается id пользователя.

В остальном механизм сессий идентичен описанному в Rails Tutorial. Советую обратить внимание на файл sessions_helper.rb и на добавление его методов в application_controller.rb

Контроллер проектов

class ProjectsController < InheritedResources::Base

  before_filter :signed_in_user, except: [:show, :index]
  before_filter :correct_user, only: [:update, :edit, :destroy]

  def show
    @project = Project.find params[:id]
    @author = @project.user.id == current_user.id if signed_in?
    show!
  end

  def create
    @project = Project.new params[:project]
    @project.user = current_user
    create!
  end

  def index
    @projects = Project.order_by(:created_at.desc)
  end

  private

    def correct_user
      @project = current_user.projects.find(params[:id])
      redirect_to root_url if @project.nil?
    end
end

Этот код интересен тем, что я использую InheritedResources Этот гем берет на себя стандартные CRUD действия для объекта. create!, show! — это вызов хелперов этого гема. Советую сходить по ссылке, там подробные примеры как это можно использовать. Ну и before_filter для ограничения доступа к созданию проекта и его редактирования.

В app/views/projects/show.html.slim я вывожу OpenID автора

= link_to @project.user.openid_identity, @project.user.openid_identity

Соответственно, если исполнителя заинтересует проект, он может свзязаться с заказчиком через его профиль на Facebook, VKontakte или LiveJournal.

Вот такая доска объявлений с минимальным функционалом у нас получилась. Нам еще нужна админка, отклики и отзывы, профили и многое много другое. Но это вполне может быть первым маленьким шагом для большой компании.

Я опустил некоторые правки, которые посчитал не существенными поэтому вам может понадобится репозиторий bitbucket.org/nleo/lancemine

Перевод документации по RoR
Ruby on Rails Tutorial: Изучение Rails на Примерах
InheritedResources
Mongoid

Автор: nleo

Поделиться

* - обязательные к заполнению поля