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
В этой статье мы рассмотрим:
- Установку Git
- Установку RVM - Ruby Version Manager для возможности работы с несколькими версиями Ruby, а также наборами библиотек Ruby - Gem’ами.
- Установку собственно Ruby: Ruby 1.8.7 и Ruby 1.9.3
- Установку SQLite, MySQL, PostgreSQL
- Установку фреймворка Ruby on Rails 3.2 и его зависимостей
- Установку Node.js как среду выполнения JavaScript
- Создание нового проекта Rails
- Работу с зависимостями проекта
- Настройку тестового окружения и написание простых спецификаций и тестов
- Написание кода приложения по спецификациям
- Установку Nginx и Unicorn, и запуск приложения Rails на Unicorn и Nginx прокси
- Работу с удаленным репозиторием
- Работу с 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 можно прочитать в .
Предложения по улучшению статьи и правки пишите в комментариях.
апреля 21, 2012 at 15:04 (#)
Спасибо за статью, парочка новых моментов я для себя отметил. Вопрос такой — планируется ли сделать чтобы код коамнд лучше подсвечивался.
И одну заметку позвольте — для установки rvm достаточно curl и git (остальное всё обычно в стандартном наборе дистрибутива стоит), а уже потом нужно установить кучу пакетов для руби :).
Ну и не плохо бы команду rvm requirements показать.
апреля 22, 2012 at 09:10 (#)
Как-то не раскрыта тема совместной работы и запуска юникорна и нгикса на более-менее реальной задаче.
апреля 22, 2012 at 16:35 (#)
none, на более-менее конкретной задаче нужно самому решить как и что должо работать так как настройки под один проект не будут оптимальными для другого. Более подробно о том, как подружить unicorn и nginx будет отдельная статья.
апреля 23, 2012 at 13:46 (#)
Добавил а закладки, спасибо!
апреля 25, 2012 at 01:47 (#)
Вы когда нибудь пробовали Unicorn + nginx на продашн ?
Обрисую ситуацию — простой rails проект , 4 воркера, каждый из них потребляет по 600МБ. Да, он быстрый, но 2,5 гига памяти на простой rails проект — это перебор.
апреля 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
над кажись подправить ))))
апреля 30, 2012 at 13:17 (#)
schemane, спасибо, поправил
апреля 30, 2012 at 15:09 (#)
Черт у меня ошибка после ввода строки:
curl -L get.rvm.io | bash -s stable пишет:
mkdir: невозможно создать каталог «/usr/share/ruby-rvm»: Отказано в доступе
Как бы и с root правами тоже самое пишет… Да вообще раньше все ставилось, а теперь… Переустановил систему…
апреля 30, 2012 at 17:58 (#)
Виталий, лучше русификацию отключи, а то потом не сможешь в интернетах искать как решить какую-либо проблему, да и вообще все стоящие руководства на английском. В чем проблема — не знаю, пропробуй вручную права директориям выставить. chmod в консоли или из файлового менеджера.
апреля 30, 2012 at 20:37 (#)
У вас опечатка в пункте 4.1 устанавливается PostgreSQL а не MySQL
апреля 30, 2012 at 23:06 (#)
Кирилл, спасибо, поправил.
июня 16, 2012 at 17:42 (#)
У меня проблема с редактированием файла pg_hba.conf. Пишет Permission deniet Можно поподробнее?
июня 17, 2012 at 06:50 (#)
kopyrin, попробуй в консоли: $ sudo nautilus — будет запущен файловый менеджер nautilus под sudo и будут все необходимые права. Или chmod от sudo выполнять нужно, если с консолью дружишь.
октября 4, 2012 at 14:09 (#)
Спасибо.
А удалось настроить связку Spork+Rspec+FactoryGirl так что бы когда Factories меняешь, Rspec перезапускался и все тесты заново прогонялись?