3 октября 2012 в 00:45

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

Я исхожу из того, что вы уже минимально знакомы с 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
+7
9249
93
nleo 0,0

Комментарии (11)

0
BorisPlus #
Интересно. Хотя и забавно вышло. Не успел ознакомиться с В пень free-lance.ru! и Free-lance.ru сошёл с ума, как вижу эту статью.
0
Aios #
И не говорите — первая мысль «Отомстить!»
0
uaweb #
Спасибо большое!
0
DarthSim #
Зачем здесь Монга? Для «попробовать» данного кода явно недостаточно, а структура, с позволения сказать, данных явно указывает на реляционные БД.
+2
UksusoFF #
Почему все упорно юзают логинзу? Она же полудохлая… чем Вам юлогин не угодил?
0
sunburn #
Полностью согласен. uLogin значительно удобнее использовать
0
nleo #
www.free-lance.ru/projects/1311641/avtorizatsiya-cherez-facebook-na-ruby.html

Человек жалуется на нестабильность юЛогина. Логинза куплена Яндексом и я думал, что она получше.
0
UksusoFF #
куплена-то куплена, но они на нее видимо забили :( нестабилен понятие относительное:
1. Мало ли как там модуль прикручен, может тот кто его делал накосячил.
2. Любой «внешний» по отношению к сайту сервис «нестабилен», у нашего провайдера например переодически недоступен гугл и как следствие не загружаются карты, jquery и прочие скрипты если они расположены не на хостинге сайта

юлогин покрайней мере быстро реагирует если происходят какие-то изменения в соц сетях.
Уж лучше тогда использовать собственную авторизацию была тут недавно статья как сделать же.
0
UksusoFF #
Вот она
–7
kliss #
> -T отказываемся от тестов

Всё, дальше можно не читать.
+3
or10n #
-T — это значит, «отказываемся от unit-тестов»,
а дальше добавляем в Gemfile провославные rspec, cucumber, etc и радуемся жизни

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.