1. Как лучше настроить VDS DigitalOcean для проектов на ruby

    И так это продолжение статьи про облачный хостинг DigitalOcean. Сегодня мы приступим к настройки виртуальной машины для проектов на ruby. Ну да я пишу на рубях, а вы что ждали? ))

    Вот такое письмо должно было вам придти после регистрации.

    Тут самое главное IP и пароль. Если ваша домашняя ОС из семейства Unix, поздравляю, а если от Microsoft соболезную и вам придется поставить ssh клиент (рекомендую Putty).

    Ну что приступим к настройке!

    ssh root@<IP addres из письма>

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

    pacman -Syu

    Данная команда скажет пакетному менеджеру забрать списки пакетов из репозитория и по необходимости обновить устаревшие. Пока не будем заострять внимание на пакетном менеджере, в дальнейшем я напишу подробную статью о нем. Сегодня будет достаточно знать, что он есть, что он умеет ставить пакеты и что его зовут pacman ))
    Если вам не терпится, то можете обратиться к официальной документации
    https://wiki.archlinux.org/index.php/Pacman_(%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9)

    UPD Возможно при обновлении вы увидите следующие строчки

    error: failed to commit transaction (conflicting files)
    filesystem: /bin exists in filesystem

    Это в связи с последними изменениями в которых перенесли все запускаемые файлы в /usr/bin. В общем ничего страшного, вам всего лишь потребуется выполнить три команды.

    pacman -Syu —ignore filesystem,bash pacman -S bash pacman -Su

    Так перейдем к установке необходимых пакетов. А собственно, что нам нужно? У меня вот такой список:

    • zsh
    • tmux
    • vim
    • git
    • rbenv
    • ruby 1.9.3
    • ruby 2.0.0
    • nginx
    • postgresql
    • redis

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

    Установка весьма простая, нужно знать лишь одну команду pacman -S

    pacman -S zsh tmux vim
    pacman -S git-core

    Тут стоит остановиться и пояснить. Для гита пакет называется git-core. А чтоб приступить к установки ruby нам нужен другой пользователь.

    useradd -m -g users -s /bin/zsh <Ваш логин>
    su <Ваш логин>
    passwd

    Этими тремя не хитрыми командами мы создаем пользователя, переключаемся на него и вызываем диалог указания пароля. Введи такой который в запомните, но отличающийся от почты и от “вконтактика”. Теперь попробуем зайти под вновь созданным пользователем. Нажмите ctrl-d, мы вернемся к пользователю root и еще раз ctrl-d закроет соединение с сервером. Теперь попробуем подключиться, но на этот раз под своим пользователем.

    ssh <Ваш логин>@<IP адрес указанный в письме>

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

    git clone https://github.com/sstephenson/rbenv.git “~/.rbenv”
    git clone https://github.com/sstephenson/ruby-build.git ”~/.rbenv/plugins/ruby-build”

    echo ‘export PATH=”$HOME/.rbenv/bin:$PATH”’ » ~/.zshrc echo ‘eval “$(rbenv init -)”’ » ~/.zshrc

    exec $SHELL -l

    И так рассказываю, что тут произошло. В начале мы склонировали два репозитория. Первый это сам rbenv (система переключения версий руби), а второй ruby-build (сборшик руби), можно конечно руками компилировать, но так удобнее. Далее добавляем путь к исполняемым файлам rbenv, чтоб наша консоль их видела и объясняем как запускать. Последняя команда перезапускает консоль/shell.

    Теперь собственно нужно поставить интерпретаторы ruby:

    rbenv install 1.9.3-p448 rbenv global 1.9.3-p448 rbenv install 2.0.0-p247 rbenv rehash

    Тут тоже все предельно просто. Первая команда ставит 1.9.3, вторая делает этот интерпритатор по умолчанию, третья ставит 2.0.0 и последняя просит rbenv обновить список исполняемых файлов, это не обязательно в данный момент, но при установки gem’ов стоит не забывать.

    План на сегодня почти выполнен, осталось поставить несколько пакетов, но для этого нужно стать root’ом

    su root

    Вводим пароль из письма, если вы его еще не поменяли, это можно сделать командой passwd, только не ставьте одинаковые пароли со своим пользователем и не забудьте его ))

    pacman -S nginx postgresql redis

    Устанавливаем последние 3 необходимых нам пакета. Это http сервер(nginx), база данных (postgresql) и key-valuy персистентное хранилище (redis)

    На этом сегодня все, задавайте вопросы, пишите о чем хотите узнать или если вдруг, что то не получилось.

    9 months ago  /  0 notes  / 

  2. Небольшой опрос

    Кто что использует для настройки своих серверов?

    1. Chef
    2. Puppet
    3. Заготовленные bash скрипты
    4. Каждый раз руками
    5. Свой вариант

    9 months ago  /  0 notes  / 

  3. DigitalOcean.com

    Время идет, а с ним растет и развивается этот ваш интернет. Появился замечательных облачный хостинг. Но не шаред, а полноценный vds с рутом и набором любых образов. Машинки в нем разворачиваются за 12 секунд, на борту имеют 512 памяти и 20 гигов жесткого, но не простого, а SSD и все это счастье обходиться в 5$ в месяц, что не может не радовать.


    Начнем с самого начала - регистрации. Да ссылка реферальная, за регистрацию по ней вы получите 10$ на счет, что равняется двум месяцам халявного использования!
    image

    Процедура весьма простая, от вас на первом этапе потребуется лишь почта и пароль.
    image

    Да предупрежу зарание, для полной регистрации и использования нужно будет ввести номер карточки. Ну вот такие правила у них ((

    image

    с карточки спишется минимальная сумма в приделах одного доллара и через пару дней вернется обратно. Это нужно для подтверждения.
    Теперь можно создавать свой первый “Droplet” так у них называются виртуальные машины. Опять же процедура весьма проста:

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

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

    Выбираем, где физически будет находиться сервер. Пока есть два варианта Нидерланды и Сан-Франциско. Для проектов с целевой аудиторией из России лучше выбрать Нидерланды.

    Осталась выбрать образ операционной системы. Вот тут вариантов на любой вкус: Ubuntu, CentOS, Debian, Arch Linux, Fedora. Поддержки *BSD в данный момент нету, но обещают сделать. В общем то исходим из своих предпочтений и опыта. Я планирую написать цикл статей по настройке, так что если хотите следовать им выберите Arch Linux х32.

    Жмем большую зеленую кнопку “Create Droplet” и ждем письма с данными для входа на почту.

    Поздравляю ваша машина готова к использованию!

    Про настройку читаем в следующих статьях, удачи.

    9 months ago  /  0 notes  / 

  4. Давно я сюда не писал ((

    Так нужно все таки как-то возобновлять блогерскую жизнь.
    За время отсутствия меня тут, многое изменилось, о это не совсем блог о личном. Так что я постараюсь описать переезд на digitalocean.com который произвожу вот прям в сейчас.

    9 months ago  /  0 notes  / 

  5. Come back day

    Сегодня что то случилось с моим мозгом, я решил вернуться во все блоги и микро блоги. Уже успел запостить парочку твитов, вернулся в жуйк и даже попробовал написать в google buzz. Вот очередь за блогом.

    Но чтобы этот пост хоть чем нибудь был полезен, я порекомендую один интересный материал про Riak это весьма продвинутое хранилище данных, причем оно будет полезно и как дб и как документо ориентируемая база (key-value store) и как склад для логов, да даже как распределенная файловая система.
    Why Riak should power your next Rails app

    3 years ago  /  0 notes  / 

  6. ActiveRecord vs SQL

    Статья старая, но в ней весьма нужная информация.

    Не всегда стоит использовать навороченные ORM иногда быстрее сделать все старым добрым SQL запросом.

    Смотрите сами. При не очень сложно но часто возникающей задачи производительность отличается в разы

    • ActiveRecord ~30 секунд в development окружении, ~22 секунды — production.
    • ar-extension ~14 секунд в development окружении, ~12 секунд — production.
    • SQL (INSERT на каждую запись) ~5 секунд в development окружении, ~3.5 секунды — production.
    • SQL (с транзакциями) ~2 секунды в development окружении, ~0.8 секунд — production
    • SQL (bulk-insert) ~0.1-0.2 секунды в production окружении!
    Вот так вот.
    У самого недавно была задача выборки из двух таблиц с фильтрацией и групперовкой. Нужно было вытащить все фильмы на которые сегодня показываются (сайт для кинотеатра), причем они выводятся на всех страницах и этот код располагается в блоке befor. Не стал использовать стандартный подход DataMapper’а, а сделал чистым SQL.
    @today = repository(:default).adapter.query(‘SELECT m.id, m.name, m.poster FROM moves m LEFT JOIN seances s ON s.move_id = m.id  WHERE s.day = ? GROUP BY m.id’, Time.now.to_day)
    Замеры не производил, но разница большая. Тут выполняется всего один запрос, а при использование find’ов DataMapper’f около 5 + еще бы пришлось самому убирать дубли.

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

    4 years ago  /  0 notes  / 

  7. Основы Datamapper

    Сейчас ORM используются повсеместно - никто не пытается работать с базой вручную. Функционал позволяет сделать многие вещи проще. Работа с ассоциациями стала в разы легче. Можно не использоватьSQL запросы , а работать с данными как с обычными объектами.

    В возможности Datamapper входит еще много разных фишек, но все по порядку. Приступим.

    Первым делом нам необходимо установить Datamapper

    gem install dm-core

    Datamapper позволяет работать с различными базами данных. Выбор и вправду впечатляет. Названия адаптеров начинаются с do_  - я напишу их рядышком в скобках. Выберите свою любимою базу или для тестов поставьте SQLite.

    Для ознакомления нам хватит SQLite  - для ее установки выполним: gem install do_sqlite3.

    Каждая таблица представляется классом, а строка - экземпляром этого класса. Datamapper поймет, что этот класс описывает таблицу, если добавить примесь include DataMapper::Resource. Такой способ позволяет наследоваться от любого другого класса. А для определения полей используется метод property с указанием названия, типа и параметров.

    require 'rubygems'require 'dm-core'# Подключение к базеDataMapper.setup(:default, 'sqlite3::memory:')# Пред идущий метод создавал базу в памяти, а так она создается на винте# DataMapper.setup(:default, "sqlite3:///#{Dir.pwd}/database.db")# Таким образом подключаться к мускулу# DataMapper.setup(:default, 'mysql://user:pass@localhost/the_database_name')  class Post    include DataMapper::Resource     property :id,         Serial    property :title,      String    property :body,       Text    property :created_at, DateTime  end    class Comment    include DataMapper::Resource     property :id,         Serial    property :posted_by,  String    property :email,      String    property :url,        String    property :body,       Text  end   class Category    include DataMapper::Resource      property :id,         Serial    property :name,       String  end  def install    DataMapper.auto_migrate!  end

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

    Попробуем поиграться с нашими табличками. Запускаем интерактивный шелл.

    $ irbirb(main):001:0> require 'file' # подгружаем созданный нами файл=> true # если все нормально ответ положительный, в противном ругнется с указанием причиныirb(main):002:0> install # Нам же нужно создать таблицы=> #<DataMapper::Model::DescendantSet:0xb7322348 @ancestors=nil, @descendants=[Post, Comment, Category]> # такое видим если результат положительныйirb(main):003:0> p = Post.new(:title => 'Освоение Datamapper\'а', :body => 'Большой текст', :created_at => Time.now) # создание первой записи=> #<Post @id=nil @title="\320\236\321\201\320\262\320\276\320\265\320\275\320\270\320\265 Datamapper'\320\260" @body="\320\221\320\276\320\273\321\214\321\210\320\276\320\271 \321\202\320\265\320\272\321\201\321\202" @created_at=#irb(main):004:0> p.save! # это отправит ее в базу=> true # подтверждение выполнения действияirb(main):005:0> # Сделайти еще несколько записей для тренировки...irb(main):006:0> Post.all # Покажет массив всех записей.=> [#<Post @id=1 @title="\320\236\321\201\320\262\320\276\320\265\320\275\320\270\320\265 Datamapper'\320\260" @body= @created_at=#irb(main):006:0> Post.first # Вернет нам первый пост=> #<Post @id=1 @title="\320\236\321\201\320\262\320\276\320\265\320\275\320\270\320\265 Datamapper'\320\260" @body= @created_at=#irb(main):007:0> # Потренируйтесь в создании комментариев и категорий...

    Здесь показана простая работа с данными, с использованием DataMapper. Мы еще вернемся к этой теме, позже. А теперь сделаем несколько ассоциаций между таблицами.

    У постов может быть много комментариев, значит здесь нужно использовать связь “один-ко-многим”.

    class Post    has n, :comments  end   class Comment    belongs_to :post  end

    Связь “один-к-одному” делается также, только используется 1 вместо n. Можно делать связи “один-к-двум” или “один-к-десяти”, просто указывая число.

    С категориями - сложнее, в одной категории может быть много постов, а у поста может быть много категорий. Здесь нужно использовать связь “многие-ко-многим”, которая реализуется через дополнительную таблицу.

    class Categorization    include DataMapper::Resource      property :id,         Serial    property :created_at, DateTime      belongs_to :category    belongs_to :post  end   class Post    has n, :categorizations    has n, :categories, :through => :categorizations  end   class Category    has n, :categorizations    has n, :posts,      :through => :categorizations  end

    Естественно, новые строки просто дополняют классы, а не переопределяют их заново. Если вносятся изменения в структуру таблиц, необходимо заново вызывать их создание.

    $ irb...irb(main):005:0> p.comments.new(:posted_by => 'ZaK', :email => 'zak@devilonrails.ru', :url => 'http://devilonrails.ru/', :body => 'Статья достойна внимания').save!=> true # p это наш пост, его придется опять создать, только что мы добавили комментарий и сразу его сохранили.irb(main):006:0> p.comments # покажет нам все комментарии к нашему посту=> [#<Comment @id=1 @posted_by="ZaK" @email="zak@devilonrails.ru" @url="http://devilonrails.ru/" @body="\320\241\321\202\320\260\321\202\321\214\321\217 \320\264\320\276\321\201\321\202\320\276\320\271\320\275\320\260 \320\262\320\275\320\270\320\274\320\260\320\275\320\270\321\217" @post_id=1>]irb(main):007:0> p.categories.new(:name => 'Первый').save! # Добавим две категории=> trueirb(main):008:0> p.categories.new(:name => 'Фото').save!=> trueirb(main):009:0> p.save! # Сохраним связи=> trueirb(main):010:0> Category.all # Подгрузим все категории=> [#<Category @id=1 @name="\320\237\320\265\321\200\320\262\321\213\320\271">, #<Category @id=2 @name="\320\244\320\276\321\202\320\276">]irb(main):011:0> c = Category.first # А теперь первую=> #<Category @id=1 @name="\320\237\320\265\321\200\320\262\321\213\320\271">irb(main):012:0> c.posts # И посмотрим какие посты есть в этой категории=> [#<Post @id=1 @title="\320\236\321\201\320\262\320\276\320\265\320\275\320\270\320\265 Datamapper'\320\260" @body=<not loaded> @created_at=#<DateTime: 70708352141/28800,5/24,2299161>>]

    Вы наверно заметили @body=<not loaded> это “ленивые” данные - Datamapper не подгружает текстовые данные сразу, а только тогда, когда они потребуются для вывода. Это поведение можно регулировать опцией :lazy => true|false для метода property. Если сейчас написать p.categories.first.body произойдет SQL запрос для выемки этих данных. А теперь давайте подумаем, что будет если постов в категории у нас 100 штук и мы хотим опубликовать их в ленте? Код простой.

    c = Category.firstc.posts.each do |p|  put p.bodyend

    Такая ситуация называется N + 1, я уже писал как Datamapper работает в таком случае. Будет сделано всего 2 запроса. Первый заберет все посты без текста, и как только мы начнем перебирать их и запрашивать body, произойдет второй запрос, который подгрузит текст для всех постов. Если мы будем перебирать категории и смотреть посты, будет использован тот же алгоритм.

    4 years ago  /  0 notes  / 

  8. Rack фреймворк для фреймворков

    Основная функция любого фреймворка сводится к обработке HTTP запросов и выдачи ответа. И так как он повторяется в каждом фреймворке Крис решил вынести его в отдельную библиотеку. Rack содержит минимальный набор функций для создания вэб приложения. Архитектура и код оптимизированы для большой производительности. Весь проект хорошо документирован.

    Выделение взаимодействия фреймворка и сервера в отдельный слой позволило создавая новый продукт, будь то сервер или фреймворк, отлаживать работу только с Rack и получать поддержку всех продуктов которые работают с Rack. На текущий момент Rack стал дефакто используемым фреймворком для фреймворков. Список поддержываемых продуктов:

    Фреймворки

    Сервера

    Сервера, поддерживаемые со стороны Rack

    Сервера, поддерживающие Rack

    Приложение написанное с использованием Rack будет запускаться на любом из этих серверов и это не потребует каких либо изменений в коде.

    Так же Rack позволяет разрабатывать модули Rack Middleware которые будут работать в любом приложении. Сегодня подходит к концу контест по написанию Rack Middleware. Там можно найти множество очень полезных модулей например rakismet - модуль позволяет проверять комментарии акисметом.

    На последок приведу простой пример Rack приложения

    class HelloWorld  def call(env)    [200, {"Content-Type" => "text/plain"}, ["Hello world!"]]  endend

    4 years ago  /  0 notes  / 

  9. Sinatra

    Sinatra это легкий DSL над Rack для быстрого создания сайтов. Сделать простое приложение займет несколько минут. Но не стоит заблуждаться, Sinatra - не конструктор с большим количеством готовых решений.

    Рассмотрим создание простой странички на классическом примере.

    require 'rubygems'require 'sinatra'get '/' do  'Hello world!'end

    Данное приложение имеет только одну страничку по адресу ‘/’ и отвечает классическим выводом “Hellow world!”

    Маршрутизация

    Для обработки путей - маршрутизации - в Sinatra используются названия HTTP методов GET, POST, PUT, DELETE. После указывается желаемый путь, а в блоке - действия, которые будут выполнены при вызове этого пути.

    get '/' do    .. чтонибудь покажем ..  end  post '/' do    .. чтонибудь создадим ..  end  put '/' do    .. чтонибудь отредактируем ..  end  delete '/' do    .. чтонибудь удалим ..  end

    Вот такой вот REST получается. Путь может содержать поименованные переменные '/user/:name' в блоке их можно будет найти в массиве params, запросив params[:name], либо указать какие параметры принимает блок. Им будут присвоены значения в порядке, указанном в пути.

    get '/hellow/:name' do    # будут обработаны запросы "GET /hello/foo" и "GET /hello/bar" ...    # значение params[:name]  'foo' или 'bar'    "Hello #{params[:name]}!"  end  get '/author/:name/book/:title' do |author,book|    # будут обработаны "GET /author/King/book/The_Dead_Zone" и другие    # при этом запросе переменная author будет содержать "King" а book "The_Dead_Zone"    ...  end

    Если точный путь указать сложно, можно использовать * например так '/download/*'

    get '/files/*.*' do    # будет обработан запрос "/files/path/to/file.xml" ...    params[:splat] # => ["path/to/file", "xml"]  end

    Для обработки запросов можно использовать regexp, что открывает огромный потенциал. Значения можно забирать из params[:] или указывать параметры для блока.

    get %r{/hello/([\w]+)} do    "Hello, #{params[:captures].first}!"  end

    Sinatra позволяет обрабатывать запросы учитывая user agent.

    get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do    "Вы используете Songbird версии #{params[:agent][0]}"  end  get '/foo' do    # Для всех остальных браузеров  end

    Шаблонизаторы

    По умолчанию для хранения шаблонов используется директория ./views. Если вы используете другую изменить можно указав set :views, File.dirname(__FILE__) + '/templates'

    Sinatra может использовать haml, erb, Builder. Можно указывать необходимые параметры.

    set :haml, {:format => :html5 } # по умолчанию Haml format стоит :xhtml  get '/' do    haml :index, :haml_options => {:format => :html4 } # можно переопределить для любого вызова  end

    Переменный можно передавать присваивая значению :locals => { }. Переменные экземпляра класса видны в шаблонах.

    get '/:id' do    @foo = params[:id]    haml '%h1= @foo + bar', :locals => { :bar => params[:id] }  end

    Маленькая хитрость если шаблон располагается в поддиректории необходимо указывать так haml :'path/name'.

    Sinatra автоматически оборачивает вывод в шаблон :layout если находит его в директории с шаблонами. Для определенных выводов можно отказаться :layout => !request.xhr?

    Helpers

    Методы указанный в блоке helpers доступны везде.

    helpers do    def bar(name)      "#{name}bar"    end  end  get '/' do    haml '%h1= bar("foo")'  end  get '/:name' do    bar(params[:name])  end

    Управление

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

    С помощь halt можно принудительно остановить выполнение запроса. Так же можно указать причину halt 'Отказано в доступе' и статус с причиной halt 401, 'Требуется авторизация'

    Если необходимо перейти к другому блоку можно использовать pass

    get '/guess/:who' do    pass unless params[:who] == 'Frank'    "Вы приглашены!"  end  get '/guess/*' do    "Оставайтесь дома!"  end

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

    configure :production do    ...  end

    Обработка ошибок

    По умолчанию любое исключение отображается специальным просмотрщиком с трейсом кода и данными запроса. Для самостоятельной отловки исключений указывается set :show_exceptions, false и используются блоки error. Для более развернутой обработки можно использовать собственные классы исключений. Информация передаваемая с исключением храниться в env['sinatra.error']

    error do    'Возникла ошибка - ' + env['sinatra.error'].message  end  get '/' do    raise MyCustomError, 'большая беда!'  end  error MyCustomError do    'Что то произошло...' + request.env['sinatra.error'].message  end

    За рамками обзора осталось использование Rack Middleware, тестирование и несколько секретов использования.

    4 years ago  /  0 notes  / 

  10. Datamapper N+1

    Есть такая ORM как DataMapper умеет делать много полезных вещей. Хорошо работает с различными типами, есть валидация данных. Сегодня я расскажу решал решенную проблему. Було нужно реализовать комментарии. Все просто запрашиваем комментарии по определенному критерию и отрисовываем их. Но каждый коммент имеет автора имя которого нужно написать рядом. Вот тут то и возникает проблема “N+1 запрос”.

    @comments = Comment.all(:page => request.page)--- haml - @comments.each do |comment|    .comment= comment.text    .author= comment.user.name

    Желая избежать кучи лишних запросов полез рыть документуху на предмет решения этой задачи. В ActiveRecord ORM для Rails все сводится к указанию :include => :users. Ожидая подобного, пробегаю документуху - нет ни чего! Озадаченно лезу в google. В конференции за 2007 нахожу мольбы о внесении данного функционала, рядом обещания авторов и тишина. Продолжаю копать потратив порядком времени узнаю, что тут оно называется “Strategic Eager Loading” и работает само! Как само, удивляюсь я. Врубаю лог, чтоб посмотреть SQL запросы и правда как только массив начинаем перебирать DataMapper сам подтягивает данные из таблицы Users.

    Вот такой вот самостоятельный!

    4 years ago  /  0 notes  /