Ruby on Rails 3: Создание и настройка рабочего окружения разработчика на Ruby и Ruby on Rails

апреля 21, 2012  |  Published in BDD, Development Processes, RSpec, Ruby, Ruby on Rails, Ruby on Rails 3, Базы данных, Основы, Тестирование  |  14 Comments

ruby on rails tutorialВ этой статье мы рассмотрим:

  1. Установку Git 
  2. Установку RVM - Ruby Version Manager для возможности работы с несколькими версиями Ruby, а также наборами библиотек Ruby - Gem’ами.
  3. Установку собственно Ruby: Ruby 1.8.7 и Ruby 1.9.3
  4.  Установку SQLite, MySQL, PostgreSQL
  5. Установку фреймворка Ruby on Rails 3.2 и его зависимостей
  6. Установку Node.js как среду выполнения JavaScript
  7. Создание нового проекта Rails
  8. Работу с зависимостями проекта
  9. Настройку тестового окружения и написание простых спецификаций и тестов
  10. Написание кода приложения по спецификациям
  11. Установку Nginx и Unicorn, и запуск приложения Rails на Unicorn и Nginx прокси
  12. Работу с удаленным репозиторием
  13. Работу с Continuous Integration (CI) сервером - Travis

 

1. Установка Git

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

Чтобы установить Git воспользуемся традиционным менеджером пакетов apt-get:

$ sudo apt-get install git

$ git —version

git version 1.7.5.4

 

Git — это программа, взаимодействие с которой происходит по средствам консоли, что не всегда бывает удобно. Для визуализации репозитория я рекомендую использовать Giggle.

$ sudo apt-get install giggle

$ giggle -v

Giggle 0.5, Copyright (C) 2007-2008 Imendio AB, Copyright (C) 2008 Mathias Hasselmann

 

2. Установка RVM

Перед установкой RVM необходимо установить несколько зависимостей:

$ sudo apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion

 

Для установки RVM воспользуемся простой консольной командой из руководства по установке RVM:

$ curl -L get.rvm.io | bash -s stable

Эта команда скачает и установит RVM для текущего пользователя. Существует возможность установки для всех пользователей системы, но нам этого не нужно.

После установки RVM его необходимо загрузить в консоль, а для этого следует воспользоваться следующей командой:

source ~/.rvm/scripts/’rvm’

Чтобы каждый раз не повторять ее ввод я рекомендую добавить ее в файл .bashrc после чего она будет загружаться автоматически при каждом сеансе работы с консолью.

Для того, чтобы узнать правильно ли установлен RVM необходимо выполнить в консоли приведенную ниже команду и получить аналогичный результат:

$ type rvm | head -n 1

rvm is a function

 

3. Установка Ruby 1.8.7 и Ruby 1.9.3

Чтобы получить список доступных для установки версий Ruby, необходимо воспользоваться приведенной ниже командой:

$ rvm list known

Нас интересуют версии MRI 1.9.3-head и MRI 1.8.7-p358 по этому мы установим только их.

 

$ rvm install 1.9.3-head

$ ruby -v

ruby 1.9.3p191 (2012-04-19 revision 35398) [i686-linux]

$ rvm install 1.8.7-p358

$ ruby -v

ruby 1.8.7 (2012-02-08 patchlevel 358) [i686-linux]

 

Проверяем какие версии Ruby установлены:

$ rvm list

rvm rubies

=> ruby-1.8.7-p358 [ i686 ]

 * ruby-1.9.3-head [ i686 ]

 

Переключение между версиями Ruby выполняется командой rvm use <version>:

 

$ rvm use 1.9.3-head

Using /home/vladimir/.rvm/gems/ruby-1.9.3-head

 

$ ruby -v

ruby 1.9.3p191 (2012-04-19 revision 35398) [i686-linux]

 

После установки Ruby необходимо определиться с тем, какая версия будет использоваться по умолчанию. Лично для меня предпочтительнее Ruby 1.9.3. Указать, какая версия Ruby будет использоваться по умолчанию можно так:

$ rvm use —default 1.9.3-head

Using /home/vladimir/.rvm/gems/ruby-1.9.3-head

$ rvm use default

Using /home/vladimir/.rvm/gems/ruby-1.9.3-head

 

4. Установка PostgreSQL, MySQL, SQLite

4.1 Установка PostgreSQL

Для установки PostgreSQL воспользуемся стандартный установщиком apt-get:

$ sudo apt-get install postgresql postgresql-server-dev-9.1

$ psql —version

psql (PostgreSQL) 9.1.3

После установки PostgreSQL необходимо настроить доступ пользователей к базе. Делается это в файле pg_hba.conf. Лично я использую следующую простую стратегию:

# TYPE  DATABASE   USER   ADDRESS   METHOD

local   all        all              trust

 

4.2 Установка MySQL

Установка MySQL очень похожа на установку PostgreSQL:

$ sudo apt-get install mysql-common mysql-server  libmysql-ruby libmysqlclient-dev $ mysql —version

mysql  Ver 14.14 Distrib 5.1.61, for debian-linux-gnu (i686) using readline 6.2

Если в ходе установки у вас возникнет ошибка:

mysql-server depends on mysql-server-5.1; however: Package mysql-server-5.1 is not configured yet.

… то, ее можно решить удалив пакет apparmor:

После этого повторите установку.

$ sudo apt-get remove apparmor 

 

4.3 Установка SQLite

На самом деле мы уже установили SQLite при установке зависимостей, однако SQLite тогда была не обязательной. Если вы не работаете над серьезным проектом, а просто хотите познакомиться с Ruby on Rails поближе, то SQLite будет для вас отличным выбором базы данных. Для установки SQLite просто воспользуйтесь командой:

$ sudo apt-get install sqlite3

$ sqlite3 —version

3.7.7 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2

 

5. Установка фреймворка Ruby on Rails

Для установки фреймворка Ruby on Rails мы воспользуемся менеджером библиотек Ruby (gem’ов), который называется совсем незамысловато -rubygems и вызывается в консоли командой gem.

Прежде чем мы установим Rails давайте создадим новый набор gem’ов - gemset. Gemset’ы используются в RVM для возможности создания нескольких рабочих окружений, каждое из которых будет обеспечено не только собственной версией Ruby, но и собственной коллекцией библиотек - gem’ов.

Создать gemset очень легко:

$ rvm gemset create rails32

‘rails32′ gemset created (/home/vladimir/.rvm/gems/ruby-1.9.3-head@rails32).

 

Смотрим список существующих gemset’ов:

$ rvm gemset list

gemsets for ruby-1.9.3-head (found in /home/vladimir/.rvm/gems/ruby-1.9.3-head)

   global

   rails32

 

Переключаемся на созданный gemset:

$ rvm use @rails32

Using /home/vladimir/.rvm/gems/ruby-1.9.3-head with gemset rails32

 

Теперь можно перейти к установке gem’ов. Для начала посмотрим на то, что у нас уже есть:

$ gem list

*** LOCAL GEMS ***

bundler (1.1.3)

rake (0.9.2.2)

rubygems-bundler (0.9.0)

rvm (1.11.3.3)

 

Ну а теперь установим Rails 3.2:

$ gem install rails -v «>=3.2.3″ —no-ri —no-rdoc

 

Флаг -v позволяет уточнить версию Rails, флаги —no-ri и —no-rdoc позволяют избежать генерации документации, что очень сильно ускорит установку фреймворка Rails и его зависимостей.

 

6. Установка Node.js

Node.js будет использоваться как окружение для выполнения JavaScript на сервере. Вам также может понадобиться Node.js для других целей, например попробовать разработку на серверном JavaScript или в работе над Rails приложением в котором некая часть будет работать на Node.js.

Установить Node.js на Ubuntu Linux так же просто, как и все остальное:

$ sudo apt-get install nodejs nmp

$ node -v

v0.4.9

$ npm -v

0.2.19

 

Вместе с Node.js мы также установили NPM - Node Package Manager — менеджер пакетов Node.js.

 

7. Создание нового проекта в Rails

Для создания нового проекта в Rails используется специальный генератор, который подготовит структуру директорий и файлов для начала работы. Вызов этого генератора осуществляется посредством команды rails new <application name>, например:

$ rails new MyApp

После выполнения генератором нового приложения своей работы, будет запущен Bundler. Bundler - это такой инструмент для управления зависимостями в приложении. Bundler установит для нашего приложения все необходимые зависимости, которые описываются в файле Gemfile.

Чтобы запустить приложение, воспользуемся командой rails s[erver]:

$ cd MyApp

$ rails s

=> Booting WEBrick

=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000

=> Call with -d to detach

=> Ctrl-C to shutdown server

[2012-04-19 21:13:46] INFO  WEBrick 1.3.1

[2012-04-19 21:13:46] INFO  ruby 1.9.3 (2012-04-19) [i686-linux]

[2012-04-19 21:13:46] INFO  WEBrick::HTTPServer#start: pid=8988 port=3000

После этого посетив http://localhost:3000 вы должны увидеть страницу приветствия.

Сгенерированное с использованием команды rails new приложение по умолчанию будет использовать базу данных SQLite. Сменить используемую базу данных в Rails не представляет труда, если приложение не использует каких-либо особенностей той или иной базы данных, однако, если вы изначально желаете использовать другую базу данных, вместо sqlite, то вам следует передать ее название в качестве параметра команде rails new:

$ rails new MyApp —database=postgresql

Используя стандартный ActiveRecord, в Rails вы можете использовать любую базу данных из списка: mysql, oracle, postgresql, sqlite3, frontbase,ibm_db, sqlserver, jdbcmysql, jdbcsqlite3, jdbcpostgresql, jdbc.

После генерации приложения необходимо отредактировать файл config/database.yml указав в нем необходимые для соединения с базой данных данные. Когда config/database.yml настроен необходимо выполнить в консоли команду:

$ rake db:create

… которая создаст базы данных для всех трех окружений (Production, Development и Test) нашего приложения.

 

8. Работа с зависимостями проекта

Очевидно, что ваш проект на Ruby on Rails будет использовать некоторые сторонние библиотеки. Забота о том, чтобы не забыть установить некоторые из них и является основной задачей управления зависимостями проекта. Для решения этой задачи используется замечательный инструмент - Bundler. Вам необходимо лишь описать зависимости вашего приложения в файле Gemfile используя простой DSL (Domain Specific Language — язык предметной области) и выполнить следующую команды:

$ bundle install

Давайте добавим в файл нашего приложения еще одну зависимость - шаблонизатор Slim, который предоставляет очень удобный язык для написания файлов представлений. Для этого в Gemfile добавим запис о gem’е slim-rails:


#Gemfile
source 'https://rubygems.org'

gem 'rails', '3.2.3'
gem 'pg'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

gem 'jquery-rails'
gem 'slim-rails'

У gem’а slim-rails в зависимостях находятся другие, необходимые ему самому gem’ы, например сам slim и потому нам не нужно описывать их все. Мы просто отмечаем то, что нам необходим slim-rails, а Bundler установит все, что нам необходимо.

Более подробно мы рассмотрим работу с Bundler в следующих частях данной статьи.

 

9. Настройка тестового окружения и написание простых спецификаций и тестов

BDD - Behaviour-Driven Development — это замечательная практика к которой я постоянно пытаюсь себя приучать. По началу сложно перепрошитьсвой мозг так, чтобы он проектировал код заранее, а не в процессе его написания. BDD позволяет оформить абстрактные мысли о том, как и что должно работать в строгую инструкцию и проверку того, работает ли код в соответствии с этой инструкцией.

Наиболее популярными инструментами для BDD являются RSpec и Cucumber и мы рассмотрим оба эти инструмента с упором на RSpec, он мне больше знаком и он более популярен. Также мы рассмотрим средства Unit-тестирования, такие как Text::Unit и MiniTest.

Для того, чтобы тесты запускались автоматически после внесения изменений в код мы будем использовать Guard, который следит за изменениями и запускает выполнение спецификаций или тестов, причем не всех, а только тех, в которых описываются сущности, которых коснулись изменения. Благодаря этому Guard — это не просто игрушка на любителя, а реально полезный инструмент, который ускоряет процесс тестирования.

Также для экономии времени мы будем использовать Spork. Spork - это DRB - сервер для тестовых фреймворков. RSpec, Cucumber, Test::Unit и т.д. запускают сервер Rails приложения при каждом своем запуске. Поскольку приложение на Rails может запускаться 5-10 секунд, то это выводит разработчиков из себя. Spork позволяет единожды запустить ваше приложение и использовать уже запущенное приложение RSpec’омили другими фреймворками.

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

Изначально в любом приложении на Rails присутствует 3 окружения: Production, Development и Test. По названию не сложно догадаться о том, для чего они предназначены, а если это для вас проблема, то учите сначала английский язык. Каждое из окружений представляет собой, с позволения сказать, набор настроек, позволяющие максимально удобно использовать приложения в тех или иных целях. Production заточено под реальную работу приложения, то есть на максимальную скорость и производительность, Development на удобство для разработчика, например, в нем отключено кэширование классов благодаря чему при обновлении страницы мы получаем новые изменения в приложении, в Production для этого потребовалось бы перезапустить сервер. Test ориентировано на выполнение тестов.

Первым этапом настройки тестового окружения является добавление всех необходимых gem’ов в Gemfile нашего приложения:


#Gemfile
source 'https://rubygems.org'

gem 'rails', '3.2.3'
gem 'pg'

group :assets do
  gem 'sass-rails',   '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
  gem 'uglifier', '>= 1.0.3'
end

group :test, :development do
  gem 'rspec'
  gem 'rspec-rails'
  gem 'minitest-rails'
  gem 'shoulda-matchers'
  gem 'cucumber'
  gem 'cucumber-rails', :require => false
  gem 'capybara'
  gem 'factory_girl_rails'
  gem 'database_cleaner'
  gem 'spork'
  gem 'spork-rails'
  gem 'guard'
  gem 'guard-spork'
  gem 'guard-rspec'
  gem 'guard-cucumber'
  gem 'rails-footnotes'
end

gem 'jquery-rails'
gem 'slim-rails'

 

После того, как все зависимости указаны выполняем команду bundle install.

Когда все зависимости установлены, мы должны «доустановить» некоторые из них в наше приложения.

Генератор RSpec доустановит RSpec в наше приложение создав необходимые файлы.

$ rails g rspec:install

      create  .rspec

      create  spec

      create  spec/spec_helper.rb

Генератор Cucumber выполняет аналогичную работу.

$ rails g cucumber:install

      create  config/cucumber.yml

      create  script/cucumber

       chmod  script/cucumber

      create  features/step_definitions

      create  features/support

      create  features/support/env.rb

       exist  lib/tasks

      create  lib/tasks/cucumber.rake

        gsub  config/database.yml

        gsub  config/database.yml

       force  config/database.yml

Команда spork настраивает Spork для работы с RSpec и Cucumber:

$ spork rspec —bootstrap

Using RSpec, Rails

Bootstrapping /home/vladimir/MyApp/spec/spec_helper.rb.

Done. Edit /home/vladimir/MyApp/spec/spec_helper.rb now with your favorite text editor and follow the instructions.

 

$ spork cucumber —bootstrap

Using Cucumber, Rails

Bootstrapping /home/vladimir/MyApp/features/support/env.rb.

Done. Edit /home/vladimir/MyApp/features/support/env.rb now with your favorite text editor and follow the instructions.

 

$ guard init

WARNING: You are using Guard outside of Bundler, this is dangerous and may not work. Using `bundle exec guard` is safer.

Writing new Guardfile to /home/vladimir/MyApp/Guardfile

 

Теперь приступим к настройке Guard. Все, что нам необходимо сделать — это описать в файле Guardfile нашего приложения то, за какими файлами должен следить Guard и что должен делать при их изменении.


#Guardfile

guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' }, :test_unit => false do

  watch('config/application.rb')
  watch('config/environment.rb')
  watch(%r{^config/environments/.+\.rb$})
  watch(%r{^config/initializers/.+\.rb$})
  watch('Gemfile')
  watch('Gemfile.lock')
  watch('spec/spec_helper.rb') { :rspec }
  watch('test/test_helper.rb') { :test_unit }
  watch(%r{features/support/}) { :cucumber }
end


guard 'rspec', :version => 2 do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }

  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml)$})                 { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  # Capybara request specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
end

guard 'cucumber' do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^lib/(.+)\.rb$})     { |m| "spec/lib/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb')  { "spec" }
  # Rails example
  watch(%r{^app/(.+)\.rb$})                           { |m| "spec/#{m[1]}_spec.rb" }
  watch(%r{^app/(.*)(\.erb|\.haml)$})                 { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
  watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#    {m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
  watch(%r{^spec/support/(.+)\.rb$})                  { "spec" }
  watch('config/routes.rb')                           { "spec/routing" }
  watch('app/controllers/application_controller.rb')  { "spec/controllers" }
  # Capybara request specs
  watch(%r{^app/views/(.+)/.*\.(erb|haml)$})          { |m| "spec/requests/#{m[1]}_spec.rb" }
end

 

Метод guard принимает в качестве аргумента название команды, которую ему следует выполнить, параметры для ее выполнения и блок кода, в котором передается информацию о том, за какими файлами необходимо следить. Команды эти не произвольные, они также называются guard’амии каждая из них предоставляется отдельным gem’ом (см. Gemfile). Метод watch в передаваемом в метод guard блоке кода используется для объявления отслеживаемых файлов и принимает в качестве аргумента шаблон — строку или регулярное выражение. Например, код:

watch('config/application.rb')

… говорит о том, что необходимо следить за файлом config/application.rb, а код:

watch(%r{^config/environments/.+\.rb$})

 

… указывает Guard’у на то, что необходимо следить за всеми файлами в config/environments и вложенных директориях, которые имеют расширение *.rb.

Мы используем три вызова метода Guard потому, что нам необходимо перезапускать Spork только при изменении некоторых файлов, которые не перезагружаются в Development и Test окружениях, в отличии от остальных. RSpec и Cucumber нам необходимо запускать практически при любых изменениях.

Теперь займемся настройкой Spork. Настройка Spork заключается в настройке того, что он должен выполнять при запуске. Для начала настроим .spec/spec_helper.rb, он должен выглядеть приблизительно следующим образом:


# .spec/spec_helper.rb

require 'rubygems'
require 'spork'

ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

require 'rspec/rails'
require 'rspec/autorun'
require 'shoulda/matchers'


Spork.prefork do
  RSpec.configure do |config|
    config.fixture_path = "#{::Rails.root}/spec/fixtures"
    config.infer_base_class_for_anonymous_controllers = false
  end
end

Spork.each_run do

end

 

Блок кода передаваемый в Spork.prefork выполняется единожды, при первом запуске RSpec, код же помещенный в блок кода передаваемы в метод Spork.each_run выполняется при каждом запуске RSpec.

После настройки взаимодействия Spork и RSpec перейдем к настройке Spork и Cucumber, к счастью она выполняется аналогичным образом:


# features/support/env.rb

require 'rubygems'
require 'spork'
require 'cucumber/rails'
require 'factory_girl/step_definitions'

Spork.prefork do
  Capybara.default_selector = :css
  DatabaseCleaner.strategy = :transaction
  Cucumber::Rails::Database.javascript_strategy = :truncation
end

Spork.each_run do

end

 

Поскольку мы используем Cucumber и factory_girl, нам необходимо подключить factory_girl/step_definitions в файл настройки Cucumber — features/support/env.rb. Чтобы не повторяться, я его уже добавил в примере выше.

Так, как мне очень нравится shoulda-matchers я решил описать процесс установки и настройки этого gem’а в данной статье. Ранее мы уже добавили shoulda-matchers в Gemfile и установили его, теперь необходимо сделать так, чтобы shoulda-matchers был доступен для использования в RSpec. Для этого нам необходимо всего лишь подключить его в файле .spec/spec_helper.rb. Чтобы не повторять код заново, я уже добавил подключение shoulda/matchers в предыдущем примере.

Теперь, когда все установлено, давайте запустим Guard, чтобы тот начал следить за файлами.

$ bundle exec guard

Guard uses NotifySend to send notifications.

Guard is now watching at ‘/home/vladimir/MyApp’

Starting Spork for RSpec, Cucumber

Using RSpec, Rails

Using Cucumber, Rails

Preloading Rails environment

Preloading Rails environment

Loading Spork.prefork block…

Loading Spork.prefork block…

Spork is ready and listening on 8990!

Spork is ready and listening on 8989!

Spork server for RSpec, Cucumber successfully started

Guard::RSpec is running, with RSpec 2!

Running all specs

No examples found.

Finished in 0.00006 seconds

0 examples, 0 failures

Running all features

Disabling profiles…

 

0 scenarios

0 steps

0m0.000s

 

На этом с настройкой тестового окружения покончено. Хочу заметить, что обычно настройка значительно проще, например, потому, что RSpec, Cucumber, Test::Unit и MiniTest очень редко используют вместе, поскольку они предназначены для одного и того же. В большинстве случаев обходятся одним единственным решением. Лично мой выбор — это RSpec.

Когда тестовое окружение настроено — настало время написания спецификаций, по которым далее будем писать код самого приложения. Мы рассмотрим написание спецификаций только на RSpec потому, что я использую только его, а с Cucumber я вообще знаком весьма поверхностно.

Чтобы не писать тесты и код приложения с нуля, мы воспользуемся генератором scaffold. Приложение, которое мы разрабатываем в контексте данной статьи совсем простое и не нуждается в каком-либо особом дизайне и по этому обойдемся минимумом кода. Приложение, которое мы напишем — это анонимные форумы. Смысл его такой: существует множество анонимных форумов, которые пользователи могут создавать без регистрации и в которые без регистрации будут писать. Таким образом мы отделаемся всего 2 простейшими моделями и двумя контроллерами. Приступаем к созданию приложения используя генераторы:

$ rails g scaffold Forum name:string comments_count:integer

invoke  active_record

      create    db/migrate/20120419223528_create_forums.rb

      create    app/models/forum.rb

      invoke    test_unit

      create      test/unit/forum_test.rb

      invoke      factory_girl

      create        test/factories/forums.rb

       route  resources :forums

      invoke  scaffold_controller

      create    app/controllers/forums_controller.rb

      invoke    slim

      create      app/views/forums

      create      app/views/forums/index.html.slim

      create      app/views/forums/edit.html.slim

      create      app/views/forums/show.html.slim

      create      app/views/forums/new.html.slim

      create      app/views/forums/_form.html.slim

      invoke    test_unit

      create      test/functional/forums_controller_test.rb

      invoke    helper

      create      app/helpers/forums_helper.rb

      invoke      test_unit

      create        test/unit/helpers/forums_helper_test.rb

      invoke  assets

      invoke    coffee

      create      app/assets/javascripts/forums.js.coffee

      invoke    scss

      create      app/assets/stylesheets/forums.css.scss

      invoke  scss

      create    app/assets/stylesheets/scaffolds.css.scss

 

$ rails g scaffold Comment nickname:string title:string content:text forum_id:integer

Для генератора Comment’ариев будет сгенерирован аналогичный набор файлов, как и в примере выше.

После того, как скелет создан необходимо выполнить команду:

$ rake db:migrate

… для того, чтобы выполнить миграции и добавить таблицы comments и forums в базу данных.

Теперь возьмемся за написание спецификаций RSpec. Структура директорий со спецификациями аналогична структуре поддиректорий директории app нашего приложения. Начнем с написания спецификаций для моделей. Наши спецификации будут совсем простыми, используяshoulda-matchers мы просто проверим обладают ли наши модели необходимым набором свойств и необходимыми ассоциациями.


# spec/models/comment_spec.rb

require 'spec_helper'

describe Comment do
  it { should have_db_column(:nickname).of_type(:string) }
  it { should have_db_column(:title).of_type(:string) }
  it { should have_db-column(:content).of_type(:text) }
  it { should belong_to(:forum) }
end


# spec/models/forum_spec.rb
require 'spec_helper'
describe Forum do
  it { should have_db_column(:name).of_type(:string) }
  it { should have_db_column(:comments_count).of_type(:integer) }
  it { should have_many(:comments).dependent(:destroy) }
end

Если после сохранения спецификаций взглянуть на результат их выполнения, то увидим следующее:

Finished in 0.10598 seconds

7 examples, 2 failures

Это называется «крассной» фазой BDD. Эта фаза заключается в том, что мы пишем спецификации перед написанием кода и естественно запуск тестов уведомит нас о том, что еще ничего из описанного в спецификации не сделано. Конкретно в данном примере не сработали 2 теста, которые проверяют ассоциации между моделями.

 

10. Написание кода приложения по спецификациям

Настало время добавить ассоциации и перейти к «зеленой» фазе BDD:


#app/models/comment.rb

class Comment < ActiveRecord::Base
  attr_accessible :content, :nickname, :title, :forum_id
  belongs_to :forum
end


#app/models/forum.rb
class Forum < ActiveRecord::Base
  attr_accessible :name
  has_many :comments
end

После сохранения изменений моделей будут автоматически запущены тесты:

Running: spec/models/forum_spec.rb

Finished in 0.08748 seconds

3 examples, 0 failures

Running all specs

…….

Finished in 0.10175 seconds

7 examples, 0 failures

Running: spec/models/comment_spec.rb

….

Finished in 0.08049 seconds

4 examples, 0 failures

 

Теперь наш код соответствует спецификациям и мы достигли «зеленой» фазы BDD, то есть закончили первую итерацию разработки.

11. Установка Nginx и Unicorn, и запуск приложения Rails на сервере Unicorn и Nginx прокси

Unicorn — это один из самых популярных Ruby веб серверов. Его успех заключается в простоте и высокой производительности. Для меня доказательством того, что Unicorn является лучшим вариантом служит то, что его использует такой замечательный проект, как Github. Недостатком Unicorn является то, что он заточен под Linux, то есть работать на Windows не будет. Не знаю, на сколько это недостаток, ведь в Development окружении вполне достаточно предустановленного сервера WebKit, а в Production никто Windows не использует.

Совместно с Unicorn мы будем использовать Nginx - самый лычший вариант для отдачи статики. Стили, скрипты, всю статику мгновенно будет отдавать Nginx, если необходимо не просто отдать статику (или кэш), то в работу включается Unicorn. Этот тандем Unicorn + Nginx обеспечивает наибольшую производительность.

 

11.1 Установка Unicorn

Чтобы использовать Unicorn в приложении на Rails необходимо добавить его в Gemfile приложения:

gem 'unicorn'

… и выполнить команду:

$ bundle install

Сразу же после установки Unicorn готов к работе. Запустить Unicorn сервер можно приведенной ниже командой:

$ bundle exec unicorn

I, [2012-04-20T14:48:56.201094 #28277]  INFO — : listening on addr=0.0.0.0:8080 fd=7

I, [2012-04-20T14:48:56.201534 #28277]  INFO — : worker=0 spawning…

I, [2012-04-20T14:48:56.202722 #28277]  INFO — : master process ready

I, [2012-04-20T14:48:56.203880 #28281]  INFO — : worker=0 spawned pid=28281

I, [2012-04-20T14:48:56.204213 #28281]  INFO — : Refreshing Gem list

I, [2012-04-20T14:49:06.382863 #28281]  INFO — : worker=0 ready

127.0.0.1 — - [20/Apr/2012 14:49:37] «GET %2Findex.html HTTP/1.1″ 200 5906 2.3581

127.0.0.1 — - [20/Apr/2012 14:49:41] «GET /rails.png HTTP/1.1″ 200 6646 3.4657

127.0.0.1 — - [20/Apr/2012 14:49:41] «GET %2Ffavicon.ico HTTP/1.1″ 200 — 0.0016

 

Однако, почти всегда необходимо сервер настраивать для того, чтобы он работал максимально эффективно. Настройка Unicorn производится в файле config/unicorn.rb. Сразу оговорюсь, что нет какой-то универсальной и подходящей всем настройки веб сервера. Оптимальные параметры могут подбираться методом проб. Ниже я приведу всего лишь очень простой вариант настройки:


# config/unicorn.rb

listen 8080 # слушаем 8080 порт, хотя он используется по умолчанию

pid "shared/pids/unicorn.pid" # указываем место хранения PID файла мастер процесса

stderr_path "shared/log/unicorn.log" # перенаправляем $stderr в логи

stdout_path "shared/log/unicorn.log" # перенаправляем $stdout в логи

worker_processes 4 # количество воркеров = количество параллельно обрабатываемых запросов

B не забудьте для shared/log и shared/pids установить права 0777.

После настройки Unicorn его следует запускать передавая адрес файла конфигурации:

$ bundle exec unicorn —config-file ./config/unicorn.rb

На этом с Unicorn закончим и перейдем к установке и настройке Nginx.

 

11.2 Установка Nginx на Ubuntu 11.04 и его настройка для работы совместно с Unicorn

Установку Nginx мы будем выполнять через знакомую нам утилиту — apt-get.

$ sudo add-apt-repository ppa:nginx/stable

$ sudo apt-get update

$ sudo apt-get install nginx

 

После этого Nginx установлен и теперь мы можем заняться его настройкой для работы с Unicorn. Тема настройки Nginx достаточно большая, чтобы ей посвятить отдельную статью. Для начала вы можете использовать готовый «» или модифицировать его по своему усмотрению.

Когда Nginx установлен и настроен, запустить его можно используя следующую команду:

$ sudo ../../etc/init.d/nginx start

 

 

12. Работа с удаленным репозиторием

Лично я пользуюсь хостингом git репозиториев, который называется Github и он мне очень нравится. Вы можете размещать на Github абсолютно бесплатно свои open-source проекты или за адекватные деньги приобрести возможность вести приватные репозитории, которые будут скрыты от сторонних глаз. Github на данный момент является, наверное, самым популярным хостингом репозиториев и на то есть реальные причины. Я рекомендуя вам использовать именно Github. Регистрация на Github очень проста и бесплатна, а новый репозиторий создается в пару кликов.

Чтобы создать репозиторий достаточно перейти в директорию с приложением и выполнить команду:

$ git init

 

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

$ git remote add <name> <repo address>

… Где <name> — псевдоним репозитория, например origin, а <repo address> — его адрес, который вам будет известен после создания репозитория на Github или другом аналогичном сервисе.

Чтобы скопировать локальный репозиторий в удаленный вам необходимо выполнить следующую команду:

$ git push -u <name>

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

После того, как в проекте сделаны какие-либо изменения, необходимо сделать коммит (или несколько) и отправить его в удаленный репозиторий:

$ git add .

$ git commit -m ‘комментарий для коммита’

$ git push <name> [<branch name>]

Чтобы применять изменения в проекте сделанные другими разработчиками необходимо переодически выполнять команду:

$ git pull <name> <branch name>

… она обновит вашу локальную ветку.

 

13. Работа с Continuous Intecration (CI) сервером Travis

Continuous Integration server (CI) — это сервер представляющий собой сервер — копию Production сервера, на котором прогоняются тесты и который, возможно, выполняет еще какие-нибудь функции, например уведомление разработчиков по email, автоматический деплой и т.д. Основная суть заключается в том, чтобы проверить как работает проект в условиях реального сервера, а не машины разработчика, где может быть совсем другое окружение и выловить ошибки до того, как они попадут на Production сервер.

является бесплатным CI сервером, который построен на основе Rails и активно используется сообществом. Travisпривязан к Github, регистрация производится через Github аккаунт в один клик и ваши репозитории обязательно должны находиться именно на Github.

Для того, чтобы Travis подхватил ваш репозиторий, в корне вашего проекта должен быть файл .travis.yml с настройкой Travis. Настройка Travisнеобычайно проста и выглядит приблизительно так:

language: ruby

rvm:

- 1.8.7

- ree

- 1.9.3

- ruby-head

gemfile:

- Gemfile

- gemfiles/rails238

- gemfiles/rails323

Travis автоматически будет переключаться между версиями Ruby и различными gemfile’ами и в результате ваше приложение будет протестировано на 4 * 3 = 12 окружения. Подробнее о настройке Travis CI можно прочитать в .

 

Предложения по улучшению статьи и правки пишите в комментариях.

Tags: , , , , , , , ,

Responses

  1. Влад says:

    апреля 21, 2012 at 15:04 (#)

    Спасибо за статью, парочка новых моментов я для себя отметил. Вопрос такой — планируется ли сделать чтобы код коамнд лучше подсвечивался.

    И одну заметку позвольте — для установки rvm достаточно curl и git (остальное всё обычно в стандартном наборе дистрибутива стоит), а уже потом нужно установить кучу пакетов для руби :).
    Ну и не плохо бы команду rvm requirements показать.

  2. says:

    апреля 22, 2012 at 09:10 (#)

    Как-то не раскрыта тема совместной работы и запуска юникорна и нгикса на более-менее реальной задаче.

  3. admin says:

    апреля 22, 2012 at 16:35 (#)

    none, на более-менее конкретной задаче нужно самому решить как и что должо работать так как настройки под один проект не будут оптимальными для другого. Более подробно о том, как подружить unicorn и nginx будет отдельная статья.

  4. anon says:

    апреля 23, 2012 at 13:46 (#)

    Добавил а закладки, спасибо!

  5. Валентин says:

    апреля 25, 2012 at 01:47 (#)

    Вы когда нибудь пробовали Unicorn + nginx на продашн ?
    Обрисую ситуацию — простой rails проект , 4 воркера, каждый из них потребляет по 600МБ. Да, он быстрый, но 2,5 гига памяти на простой rails проект — это перебор.

  6. schamane says:

    апреля 29, 2012 at 23:06 (#)

    в коде дубляж строк

    #app/models/comment.rb

    class Comment < ActiveRecord::Base
    attr_accessible :content, :nickname, :title, :forum_id
    belongs_to :forum
    end

    #app/models/forum.rb
    class Comment < ActiveRecord::Base
    attr_accessible :content, :nickname, :title, :forum_id
    belongs_to :forum
    end

    над кажись подправить ))))

  7. admin says:

    апреля 30, 2012 at 13:17 (#)

    schemane, спасибо, поправил

  8. Vitaliy says:

    апреля 30, 2012 at 15:09 (#)

    Черт у меня ошибка после ввода строки:
    curl -L get.rvm.io | bash -s stable пишет:
    mkdir: невозможно создать каталог «/usr/share/ruby-rvm»: Отказано в доступе

    Как бы и с root правами тоже самое пишет… Да вообще раньше все ставилось, а теперь… Переустановил систему…

  9. admin says:

    апреля 30, 2012 at 17:58 (#)

    Виталий, лучше русификацию отключи, а то потом не сможешь в интернетах искать как решить какую-либо проблему, да и вообще все стоящие руководства на английском. В чем проблема — не знаю, пропробуй вручную права директориям выставить. chmod в консоли или из файлового менеджера.

  10. says:

    апреля 30, 2012 at 20:37 (#)

    У вас опечатка в пункте 4.1 устанавливается PostgreSQL а не MySQL

  11. admin says:

    апреля 30, 2012 at 23:06 (#)

    Кирилл, спасибо, поправил.

  12. kopyrin says:

    июня 16, 2012 at 17:42 (#)

    У меня проблема с редактированием файла pg_hba.conf. Пишет Permission deniet Можно поподробнее?

  13. admin says:

    июня 17, 2012 at 06:50 (#)

    kopyrin, попробуй в консоли: $ sudo nautilus — будет запущен файловый менеджер nautilus под sudo и будут все необходимые права. Или chmod от sudo выполнять нужно, если с консолью дружишь.

  14. Bighamster says:

    октября 4, 2012 at 14:09 (#)

    Спасибо.
    А удалось настроить связку Spork+Rspec+FactoryGirl так что бы когда Factories меняешь, Rspec перезапускался и все тесты заново прогонялись?

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.