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