Показаны сообщения с ярлыком rails. Показать все сообщения
Показаны сообщения с ярлыком rails. Показать все сообщения

воскресенье, 5 мая 2013 г.

Как работал ovirt в 2008 пока его не переписали на мерзкой яве.

Начало использования
Устанавливаем конфиг репозитория ovirt
rpm -ih http://ovirt.org/repos/ovirt/ovirt-release-LATEST.noarch.rpm
Обновляемся используя новый репозиторий
yum update --enablerepo=ovirt -y
либо можно подредактировать конфиг /etc/yum.repos.d/ovirt.repo
и заменить enabled=0 на enabled=1 (теперь всегда по умолчанию он у нас включен)
yum update -y

И ставим необходимые нам пакеты (может занять до 500мб)
yum install --enablerepo=ovirt ovirt-appliance ovirt-docs ovirt-node virt-viewer-plugin qemu-img

и перезапускаем libvirtd
service libvirtd restart
При условии что обородувание поддерживает виртуализацию и подгружен модуль kvm начинаем ставить виртуальный сервер, можно сказать управляющий - все управление происходить будет с него.
Интерфейс которым подключены к локальной сети eth0 - его и укажем
create-ovirt-appliance -e eth0
После этого сделайте
ifdown eth0
ifconfig eth0 /<маска сети> up

Теперь запустим виртуальную машину
virsh start ovirt-appliance

Так же можно понаблюдать за процессом загрузки (при желании даже вмешаться) запустив

virt-viewer ovirt-appliance

Пароль root по умолчанию ovirt.

Адрес панели управления, по умолчанию 192.168.50.2/ovirt
Доступ в панель ovirtadmin/ovirt

Не советую переименовывать hardware pool с именем default. Оказывается что в коде жестко прописано DEFAULT_POOL_NAME = "default". Можете догадаться как я это узнал... конечно переименовал и потом искал в чем ошибка:)

Если хочется покопаться в коде то желательно получить документацию
У меня встретился досадный баг "uninitialized constant RubyToken::AlreadyDefinedToken"
По первому же запросу гугл подсказал что необходимо в файле Rakefile переместить "require 'gettext/utils'" в задачи только нуждающиеся в нем (make_mo и update_po).

Генерируем документы по коду
rake doc:app.

При неудачном завершении работы виртуальной машины на которой крутился ovirt лучше всего - перед загрузкой успеть в меню загрузчика grub
нажать 'e'
выбрать вторую строку и опять 'e'
написать через пробел цифру 1
потом enter и 'b'
таким образом мы загрузимся в singlemode режиме
и запустим проверку диска fsck /dev/sda2
потом просто перезагружаемся /sbin/init 6
должно нормально загрузится

#################редактировать###################
Общение между физическими серверами происходит (как я понял ) по протоколу amqp используя демон qpid.
На добавляемой физической ноде необходимо запустить
ovirt-install-node stateful
также сделал

create-ovirt-appliance -e eth1
затем понял что в сети должны видеть друг друга не только физические ноды но и виртуальная управляющая
потому подключаем ovirtbr0 к локальной сети
сначала brctl addif ovirtbr0 eth0 добавляем интерфейс к мосту
затем ifconfig eth0 down ; ifconfig eth0 0.0.0.0/0 up; что б могли с любых подсетей получать пакеты
так же и на второй ноде
проверив все пингом пытаемся найти в списке необходимые нам физические сервера
################################################

При запуске libvirtd он рассылает multicast dns (224.0.0.251) сообщение о том что запущен libvirt. Ответственный за это демон avahi.

На управляющем сервере в директории рельсов лежит host-browser.rb он слушает на 12120 порту тср запросы с управляемых физических узлов.

На физ узлах есть скрипт /etc/init.d/ovirt ставим аргумент старт и он посылает сообщения на узел с которого грузился

/usr/sbin/ovirt-identify-node отправляет на указаный сервер информацию о узле
после того как он отработает - создается запись
теперь найти как она должна создаваться автоматом

На управляемой ноде в файле /etc/init.d/ovirt-functions определяются основные конфигурационные параметры - в частности порт и сервер управления



суббота, 28 января 2012 г.

deploy spree to openshift

Instruction how to deploy spreecommerce to openshift
work with ruby 1.8.7 because openshift work with this version.
ruby 1.9. hash syntax will create problem in openshift cloud

1. create application on openshift
rhc-create-app -a spree -t rack-1.1
Создалось приложение в облаке редхата и папочка spree с простым rack приложением.
А нам надо создать rails приложение с гемами spree.
rm -f ./spree/README
rails new ./spree -d postgresql -f
Обратите внимание - используем постгрес(дело вкуса конечно,но все ж знают, что постгрес вкуснее)
2. add database(postgresql)
rhc-ctl-app -a spree -e add-postgresql-8.4
Если понадобится удалить подключенную базу
rhc-ctl-app -a spree -e remove-postgresql-8.4
По завершению мы получим данные для подключения к базе.
Их стоит записать в spree/config/database.yml
и не забудьте добавить поле host и вписать ip из подобной строки Connection URL: postgresql://127.1.13.1:5432
И настроить базу для development режима
development:
  adapter: sqlite3
  database: db/dev.sqlite3

И в Gemfile добавляем гем sqlite3 для группы development
теперь перемещаемся в папку spree
bundle install && bundle exec rails g spree:install
добавляем сприи в Gemfile
echo "gem 'spree', :git => 'git://github.com/spree/spree.git'" >> ./Gemfile
Gemfile.lock должен быть актуальным
bundle install
mkdir public/images && cp public/favicon.ico public/images/favicon.ico
RAILS_ENV=development bundle exec rake assets:precompile

добавить код в .openshift/action_hooks/deploy

pushd ${OPENSHIFT_REPO_DIR} > /dev/null
RAILS_ENV=production bundle exec rake db:migrate -y
RAILS_ENV=production bundle exec rake db:seed -y
popd > /dev/null


и теперь пушим git push
после удачного деплоя очищаем .openshift/action_hooks/deploy

first request will broken - it is problem on timeout parameter in proxy server.
but exist problem with timeout

P.S.
after few updates require use this database.yml


adapter: <%=ENV['OPENSHIFT_DB_TYPE']%>
encoding: utf8
host: <%=ENV['OPENSHIFT_DB_HOST']%>
port: <%=ENV['OPENSHIFT_DB_PORT']%>
socket: <%=ENV['OPENSHIFT_DB_SOCKET']%>
database: <%=ENV['OPENSHIFT_APP_NAME']%>
username: <%=ENV['OPENSHIFT_DB_USERNAME']%>
password: <%=ENV['OPENSHIFT_DB_PASSWORD']%>

воскресенье, 14 августа 2011 г.

Кеширование в мультидоменном веб приложении

добавляем в контроллер

before_filter { |c|
   c.class.page_cache_directory = "#{RAILS_ROOT}/public/#{c.request.host}"
}

в логах сразу видим как пишется

Write fragment views/sub.domain.com/s/test (2.6ms)

и при повторном запросе

Read fragment views/sub.domain.com/s/test (0.9ms)

Итого: с 300мс до 10 мс рендеринг страницы.

среда, 3 августа 2011 г.

Получение в SproutCore нескольких массивов данных одним запросом к бакэнду.

Получение нескольких массивов данных одним запросом к бакэнду.

Допустим, у нас есть приложение Blog, в котором есть модели Blog.Post и Blog.Quote. Пусть они выводятся сервером по адресу '/records.json' и в json выглядят вот так:
{posts: [{post1}, {post2}, {post3}], quotes: [{quote1}, {quote2}, {quote3}]}
Что бы уменьшить количество запросов к серверу и тем самым увеличить скорость получения данных, нам нужно немного изменить datasource приложения.
Шаг 1. Создать запрос:
Blog.QUERY_POSTS_AND_QUOTES = SC.Query.local([Blog.Post, Blog.Quote]);
В SC.Query.local можно передавать не только один тип записи, но и массив типов.
Шаг 2. Создать хэш-таблицу с ссылками на данные и типами записей:
Это шаг нужен что бы избежать огромного количества if в функции fetch()

Blog.Datasource = SC.DataSource.extend({
   urls: {
     posts_and_quotes: { url: '/records.json', records: ['posts', 'quotes'] }
   },
});

Так же нам нужно поправить шан запрос, установив ему атрибум id, соответствующий имени одного из элементов urls, в данном случае posts_and_quotes:
Blog.QUERY_POSTS_AND_QUOTES = SC.Query.local([Blog.Post,Blog.Quote]).set('id','posts_and_quotes');
Шаг 3. Пишем fetch():

fetch: function(store, query) {
   //Получаем id запроса и берём из urls ссылку для запроса в соответствии с этим id
   var id = query.get('id');
   //Если id не задан, значит запрос не должен обращаться к серверу
   if(!id) return NO;
   var url = this.urls[id]['url'],
     funcs = this.get('fetchDidComplete'),
     //Если нужна особая обработка какого нибудь запроса то в fetchDidComplete
     //нужно добавить функцию, имя которой совпадает с id (ещё одна хэш-таблица).
     //Если имя не указано, то по завершении запроса будет вызвана default функция

     func = funcs[id] || funcs['default'];
   SC.Request.getUrl(url).json().notify(this, func, store, query).send();
   return YES;
}



Шаг 4. Обрабатываем полученные данные:

fetchDidComplete: {
   'default': function(response, store, query) {
     if (SC.ok(response)) {
       //В зависимости от id берём нужные записи из полученного json
       var body = this.urls[query.get('id')]['records'];
       //Получаем тип записи
       var recordType = query.get('recordType');
       //Если тип не задан, значит их несколько и они хранятся в recordsTypes
       if (!recordType) {
       var recordTypes = query.get('recordTypes'); //Получаем типы записей
       jQuery.each(body, function(i) {
       //Загружаем в store записи разных типов. Порядок выдачи записей разных типов сервером
       //и порядок этих типов в запросе должны совпадать. Т.е.:
       //SC.Query.local[Scm.Product, Scm.Taxon] и {products: [{product1}, {product2}], taxons: [{taxon1}, {taxon2}]}

       store.loadRecords(recordTypes[i], response.get('body')[body[i]]); });
     }
     else {
       store.loadRecords(recordType, response.get('body'));
     }
     store.dataSourceDidFetchQuery(query);
     } else store.dataSourceDidErrorQuery(query, response);
   }
}


Шаг 5. Используем новый запрос в приложении:
var data = Blog.store.find(Blog.QUERY_POSTS_AND_QUOTES);
Теперь, что бы получить отдельно posts, а отдельно quotes используем scoped queries:

var posts = data.find(SC.Query.local(Blog.Post);
var quotes = data.find(SC.Query.local(Blog.Quote);

Ну и теперь можно заполнить ArrayController'ы приложения полученными данными:

Blog.postsController.set('content', posts);
Blog.quotesController.set('content', quotes);

Полностью datasource будет выглядеть так:
Blog.Datasource = SC.DataSource.extend({
urls: {
   posts_and_quotes: { url: '/records.json', records: ['posts', 'quotes'] }
},
fetch: function(store, query) {
   //Получаем id запроса и берём из urls ссылку для запроса в соответствии с этим id
   var id = query.get('id');
   //Если id не задан, значит запрос не должен обращаться к серверу
   if(!id) return NO;
   var url = this.urls[id]['url'],
     funcs = this.get('fetchDidComplete'),
     //Если нужна особая обработка какого нибудь запроса то в fetchDidComplete
     //нужно добавить функцию, имя которой совпадает с id (ещё одна хэш-таблица).
     //Если имя не указано, то по завершении запроса будет вызвана default функция
     func = funcs[id] || funcs['default'];
   SC.Request.getUrl(url).json().notify(this, func, store, query).send();
   return YES;
},
fetchDidComplete: {
   'default': function(response, store, query) {
   if (SC.ok(response)) {
     //В зависимости от id берём нужные записи из полученного json
     var body = this.urls[query.get('id')]['records'];
     //Получаем тип записи
     var recordType = query.get('recordType');
     //Если тип не задан, значит их несколько и они хранятся в recordsTypes
     if (!recordType) {
       var recordTypes = query.get('recordTypes'); //Получаем типы записей
       jQuery.each(body, function(i) {
       //Загружаем в store записи разных типов. Порядок выдачи записей разных типов сервером
       //и порядок этих типов в запросе должны совпадать. Т.е.:
       //SC.Query.local[Scm.Product, Scm.Taxon] и {products: [{product1}, {product2}], taxons: [{taxon1}, {taxon2}]}
       store.loadRecords(recordTypes[i], response.get('body')[body[i]]); });
     }
     else {
       store.loadRecords(recordType, response.get('body'));
     }
     store.dataSourceDidFetchQuery(query);
     } else store.dataSourceDidErrorQuery(query, response);
     }
   },
});

вторник, 2 августа 2011 г.

Tradefast & Sproutcore 1.6: Создание и использование тем

Tradefast & Sproutcore 1.6: Создание и использование тем
В этом небольшом руководстве описывается процесс создания и последующего использования своей темы для sproutcore-приложения, импользующего handlebars в качестве шаблонизатора.

В самом простом (и наиболее часто используемом) случае, тема - это набор css-стилей. Помимо этого темы могут заменять DOM, сгенерированный через views приложения.

Создадим новую тему командой sc-gen theme и назовём её tradefast-red:

sc-gen theme tradefast-red
~ Created directory at themes/tradefast_red
~ Created directory at themes/tradefast_red/resources
~ Created file at themes/tradefast_red/resources/theme_styles.css
~ Created file at themes/tradefast_red/theme.js
~ Created file at themes/tradefast_red/Buildfile
Your theme is now ready to use!


Sproutcore добавил в /themes (если этой папки нет, то она так же будет сгенерирована) папку /tradefast_red, в которой хранятся все необходимые для темы файлы. В main.js определяется новая тема и добавляется в приложение:

TradefastRed = SC.AceTheme.create({
name: 'tradefast-red'
});
SC.Theme.addTheme(TradefastRed);


По-умолчанию новая тема создаётся как под-тема темы Ace, которая не нужна, если приложение использует handlebars. Поэтому лучше удалить ‘Ace’ из определения темы:
TradefastRed = SC.Theme.create

Так же стоит убрать ace из tradefast_red/Buildfile:
Было: config :tradefast_red, :css_theme => 'ace.tradefast-red'
Стало: config :tradefast_red, :css_theme => 'tradefast-red'

В папке /resources находятся стили вашей темы, по-умолчанию это файл theme_style.css, но вы можете добавлять сколько угодно css-файлов. В этой же папке стоит хранить все изображения, связанные с темой.

Что бы использовать тему в приложении, нужно указать её в Buildfile самого приложения, который лежит на одном уровне с папками /themes и /apps:
config :all, :required => :sproutcore', :theme => "tradefast_red"
Обратите внимание, что имя темы совпадает с именем папки с темой в /themes/. Не перепутайте с именем, указанном в main.js. :theme => “tradefast-red” не сработает.

Остаётся только перезапустить сервер sc-server и посмотреть на новую тему в действии.

Внимание: не рекомендуется при использовании тем создавать css внутри самого приложения, так как эти стили определяются до темы и переписывают все правила, заданные в вашей теме. Вместо того что бы портить css кучей !important, лучше хранить полный css в каждой теме отдельно. Такой подход так же позволит переопределять макет приложения без лишних телодвижений.

суббота, 6 ноября 2010 г.

tranz

Быстро добавляем платежные системы и транзакции в проект
https://github.com/pronix/tranz

Ставим плагин

rails plugin install git://github.com/pronix/tranz.git
rails g tranz

Если все получилось удачно - то удаляем плагин

rails plugin remove tranz

суббота, 9 октября 2010 г.

defer for javascript_include_tag

Причин не использовать defer (отрисовку страницы не дожидаясь загрузки элементов src с данным тегом).
Первый порыв писать патчик был высмеян после изучения кода contant_tag.
Уже все есть.

= javascript_include_tag %w(application.js jquery.min.js jquery.progressbar.min.js rails.js) , :defer => true


четверг, 26 августа 2010 г.

Оптимизация миграций(перевод)

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


1. Индексы базы данных
В первую очередь определите индексы для всех внешних ключей и для всех колонок которые вы будете сортировать, по которым будете искать и группировать.
class CreateInvoices ActiveRecord::Migration
  def self.up
    create_table :invoices do |t|
      t.integer :number
      t.integer :year
      t.decimal :total_amount
      t.date :invoice_date
      t.integer :company_id
      t.integer :client_id
      t.timestamps
    end
  end
  def self.down
    drop_table :invoices
  end
end

Это обычная миграция генерируемая стандартной script/generate коммандой.
Теперь добавим индексы для сортируемых полей и ключей.

class CreateInvoices ActiveRecord::Migration
  def self.up
    create_table :invoices do |t|
      t.integer :number
      t.integer :year
      t.decimal :total_amount
      t.date :invoice_date
      t.integer :company_id
      t.integer :client_id
      t.timestamps
    end
  end
  add_index :invoices,:company_id
  add_index :invoices,:client_id
  add_index :invoices,:number
  add_index :invoices,:year
  def self.down
    drop_table :invoices
  end
end

Индексы важны для производительности.
База начинает летать по сравнению со стандартной миграцией.
Есть несколько плагинов которые будут полезны для вашей базы.
* http://github.com/eladmeidar/rails_indexes
* http://github.com/mlomnicki/automatic_foreign_key
* http://github.com/samdanavia/ambitious_query_indexer


2. Пишите сиды.
Начиная с рельсы 2.3.4 вместо того что б вписывать данные в миграции - пишите их в seed.rb
Обращаю внимание - фикстуры для тестов,сиды для продакшена(содержит данные без которых нельзя стартануть- например список странн или список станций метро)

обход callback в рельсе

1: не в курсе как обновить атрибуты и сохранить модельку без валидации?
2: u.attributes = {:tt => 12, :yu => 78} u.save(false)
1: пасиба, а не в курсе как избежать before/after коллбеков?
2: вроде как то отключать можно
1: @user_profile.send(:update_without_callbacks)