SQLite + RoR + Ubuntu

21 августа 2009

Записываю, чтобы не забыть.

Ставим:

 sudo apt-get install sqlite3 libsqlite3-dev
 sudo gem install sqlite3-ruby
И все!

Linux tips: job running time

13 июля 2009

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

time cmd

Примеры:

time rake db:migrate

Покажет сколько времени проходила миграция, это может быть полезным если вы производите в миграции конвертирование данных а не только изменение схемы.

MySQL tips: optimize tables

3 июня 2009

Задача: оптимизировать все таблицы в базе.

Решение:

mysql -u user -ppassword database -e "show tables"\
   | grep -v Tables_in | grep -v "+" \
   | gawk '{print "OPTIMIZE TABLE  " $1 ";" }' \
   | mysql -u user -ppassword database

MySQL tips: change all tables engine for database

26 мая 2009

Задача: Конвертнуть одним махом все таблицы из MyISAM в InnoDB

Решение:

mysql -u user -ppassword database -e "show tables"\
  | grep -v Tables_in | grep -v "+" \
  | gawk '{print "ALTER TABLE " $1 " ENGINE = InnoDB;"}' \
  | mysql -u user -ppassword database

Factory girl: extract_factories

19 мая 2009

Все наверное слышали о фабиках от Thoughtbots, а кто не слышал услыште.

Ставим все очень просто:

 gem install thoughtbot-factory_girl --source http://gems.github.com

А дальше курим доку и радуемся жизни.

О птичках, наваял тут скриптец для построения фабрик, который достаточно скопировать себе в директорию lib/tasks/

Использовать:

rake db:extract_fixtures

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

shoulda: running concrete context

5 мая 2009

Многие Rails разработчики уже используют shoulda - замечтельный  BDD фреймворк от команды thoughtbot, как альтернативу rspec, например.

Сам фреймворк - это надстройка над UnitTests.

При разработке с  UnitTests часто возникает необходимость запустить отдельный тест и посмотреть результаты. Но как быть с shoulda - ведь названия тестов здесь это обычные текстовые предложения, которые формируются с учетом контекста теста и контекстов в котором тест находится. Например:

require File.dirname(__FILE__) + '/../test_helper'
require 'shoulda'

class ArticleTest < Test::Unit::TestCase
  fixtures :all
  context "On create" do
    should "create article if all params ok" do
      article = Article.new( :title => "shoulda rocks", :body => "Try it")
    end
    should "require title" do
      article = Article.new(:body => "That article wouldn't be published")
    end
    should "require body" do
      article = Article.new(:title => "Where is my body?")
    end
  end
end

В таком случае shoulda сгенерит следующие тесты:

test: On create should create article if all params ok
test: On create should require title
test: On create should require body

Пока у нас не много тестов все ок. Но если у нас большое количество контекстов, например, On Create, On  Update, On Destroy и т.д.? И мы хотим выполнить определенный контекст для того чтобы понять где именно проблема.

Для этого воспользуемся возможностью UnitTests запускать отдельные тесты с ключем -n

Test::Unit automatic runner.
Usage: test/unit/shop_test.rb [options] [-- untouched arguments]

    -r, --runner=RUNNER          Use the given RUNNER
                                 (c[onsole], f[ox], g[tk], g[tk]2, t[k])
    -n, --name=NAME              Runs tests matching NAME.
                                 (patterns may be used).
    -t, --testcase=TESTCASE      Runs tests in TestCases matching
                                 TESTCASE. (patterns may be used).
    -I, --load-path=DIR[:DIR...] Appends directory list to $LOAD_PATH.
    -v, --verbose=[LEVEL]        Set the output level (default
                                 is verbose). (s[ilent],
                                 p[rogress], n[ormal],v[erbose])
        --                       Stop processing options so that the
                                 remaining options will be passed to the
                                 test.
    -h, --help                   Display this help.
Deprecated options:
        --console                Console runner (use --runner).
        --gtk                    GTK runner (use --runner).
        --fox                    Fox runner (use --runner).

Как показывает нам справка, параметром ключа -n может быть любое регулярное выражение. Например, команда:

ruby test/unit/article_test.rb --name="/test:(.*)On create(.*)/"

запустит на выполнение только тесты из контекста On create.

Вот так вот.

rake gems:install

3 мая 2009

В версию rails 2 была добавлена интересная возможность установки зависимых gem библиотек используя только 1 команду. Для этого Вам необходимо вписать в environment.rb следующие строки, например для установки will_paginate:

    config.gem 'mislav-will_paginate', :version => '~> 2.3.8',
      :lib => 'will_paginate',
      :source => 'http://gems.github.com'

После этого в командной строке нужно набрать rake gems:install. Но не все так просто.

Если у Вас есть rake task в котором Вы, например включаете  environment.rb то Вы получите интересное сообщение, примерно такое:

sudo rake gems:install
(in /home/cthulhu/development/blog)
Missing these required gems:
  mislav-will_paginate  ~> 2.3.8

You're running:
  ruby 1.8.6.111 at /usr/bin/ruby1.8
  rubygems 1.3.2 at /home/cthulhu/.gem/ruby/1.8, /usr/lib/ruby/gems/1.8

Run `rake gems:install` to install the missing gems.

ИМХО это еще хуже чем драйвера для вашего CD на CD.

Существует пара хаков против такого поведения.

Плохой, ИМХО, - подхачить rail. Для этого в файле rails/lib/gems.rake в блоке:

namespace :gems do
  task :base do
    $gems_rake_task = true
    require 'rubygems'
    require 'rubygems/gem_runner'
    begin
      Rake::Task[:environment].invoke
    rescue
    end
  end
  ...
end

Нужно заменить:

 Rake::Task[:environment].invoke

на

begin
  Rake::Task[:environment].invoke
 rescue
end

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

Второй вариант, более преемлемый - дописать в  environment.rb небольшой хак вида:

if $rails_gem_installer
  class Rails::Initializer
    def load_application_initializers; end
  end
  config.gem 'mislav-will_paginate',
    :version => '~> 2.3.8', :lib => 'will_paginate',
    :source => 'http://gems.github.com'
end

Переменная $rails_gem_installer будет установлена когда Вы будете вызывать рейк таски из семейства установки гемов.

Так вот.

Может кто знает более правильные способы решения этой проблемы?

TDD mantra RED/GREEN/REFACTOR in tha Rails

30 апреля 2009

Все слышали о TDD мантре красный, зеленый, реорганизация. Чтобы все было именно так, в рельсах нужно 2 вещи autotest и плагин redgreen.

Создаем в корне прожекта файлик .autotest и пишем в него 1 строчку require ‘redgreen/autotest’. Далее стартуем как обычно:

autotest -rails

И вуаля, консоль с тестами красно/зеленая.

MySQL tips: drop all tables from database

29 апреля 2009

Маленький скриптец для удаления всех таблиц из БД:

mysql -u user -ppassword db_name -e "show tables"\
  | grep -v Tables_in | grep -v "+" \
  | gawk '{print "drop table " $1 ";"}' \
  | mysql -u user -ppassword db_name

Еще можно написать хранимую процедуру для этого, примерно так:

delimiter $$
DROP PROCEDURE IF exist drop_tables();
create procedure drop_tables()
begin
  SELECT
    @drop_sql:=concat('DROP TABLE IF EXISTS ', group_concat(table_name))
    drop_statement
  FROM information_schema.tables
  WHERE table_schema=database();
  IF (@drop_sql IS NOT NULL) THEN
    PREPARE stmt from @drop_sql;
    EXECUTE stmt;
    DROP PREPARE stmt;
  END IF;
end$$
delimiter ;

Вот так вот.

MySQL MyISAM + rails tests = bugs

29 апреля 2009

Пришлось мне на днях потюнить MySQL. Решил попробовать разные конфигурации на предмет максимальной производительности по моим задачам. Нарыл ряд статей по  улучшению производительности. Лучше всего ИМХО написано было сдесь.

Пред история. Сразу скажу что запросы у меня простые и короткие. Пара селектов по индесированым полям + инсерт + апдейт. Ничего сложного. Но! В один прекрасный момент СУБД просто брала и начинала жрать все ресурсы процессора как локально так и на продакшин сервере. Однодневный инвестигейт показал интересную вещь. После инсерта происходит перестрой индексов данной таблицы, что само по себе требует ресурсов процессорного времени и это время прямо пропорционально количеству записей в таблице. Таким образом, если мне нужно много циклов записей/селектов подряд то время каждого цикла начинает расти. И у меня оно дошло до 1го цикла в секунду. Это при том что мне нужно это сделать 300к-500к раз. Посчитав примерно во что мне это обойдется вышло что весь цикл будет длиться с недельку. Это естественно ни в какие рамки не лезет.

Посему начал рыть. Сначала в сторону тюнинга СУБД. В целом добился прироста производительности гдето на 10%. Но проблема как обычно была не в СУБД. Т.е. как-бы в СУБД но не в СУБД. В общем это не самое интересное.

Самое интересно это то, что вовремя тюнинга я настроил все базы на использования движка MyISAM. И тут начались спец-эффекты. Упало ряд тестов. Анализ кода ничего не показал. Анализ фикстур, откаты изменений (я работаю в команде посему начал грешить на последние комиты) все это ни к чему не привело.

Начал думать (гуглом). Как оказалось тесты в рельсах работают (в основном) в режиме транзакций. Т.е. каждый тестовый случаю выполняется как транзакция, которая потом (после выполнения тестового случая) откатывается. Теперь о MyISAM, как извесно этот движек не поддерживает транзакций, поэтому ряд тестов модифицируют данные необратимо. С этим и были связаны глюки. Кроме того, глюки будут также если у вас есть модифицирующие хранимые процедуры.

Вердикт. Для тех кто использует MySQL в тестовых версиях используйте движек InnoDB, иначе могут выпасть очень даже интересные глюки. Или используйте PostgreSQL.

Блог работает на WordPress.
Подписка RSS: все записи, комментарии.