Персональный блог Баобаба

Как выделить модели приложения в отдельный проект

  •  
February 24, 2014 18:043 коммент.

Имеется один проект, который хочется разделить на 3 отдельных проекта - приложения:

  • для пользователей,
  • для админов,
  • для партнеров.

Все три приложения должны использовать общие модели, а также связанные с моделями другие сущности: миграции, сериализаторы, rspec тесты моделей, сериализаторов, сервисный код, определенный в {Rails.root}/lib .

Хочется иметь отдельный 4-й проект для всех этих сущностей, который можно:

  1. отдельно дорабатывать и тестировать,
  2. легко подключать к  трем приложениям,
  3. тестировать, либо не тестировать совместно с приложениями.

Пока остановился на варианте выделения кода моделей и связанных сущностей в gem и помещения его в vendor/gems.

Почему не Engine? Потому что ни моделей, ни контроллеров, ни маршрутов, ни js, css я помещать в него не собираюсь.

Необходимо сделать:

  1. Создать структуру каталогов gem-а, написать gemspec
  2. Настроить тестовое окружение rspec тестов gem-а, максимально приближенное к тестовому окружению проектов
  3. Перенести содержимое lib в gem
  4. Выполнить вызов rspec тестов gem-а
  5. Выполнить вызов миграций gem-а
  6. Подключить gem в проектах приложений
  7. Версионировать gem
  8. Настроить тегирование Vim для перехода к определению методов/классов/модулей по тегам.

Хочу в этом посте описать процесс выделения этого gem-а, достоинства и недостатки этого метода разделения кода между приложениями.

27 февраля

Выяснил, что все-таки будет необходим engine gem, т.к. Надо расшарить и миграции и так, чтобы они вызывались без копирования в хостовое приложение при помощи генераторов. Также решил поместить в engine некоторые css, coffeescript ресурсы и ApplicationController. Также хотелось бы расшарить config/[initializers, application.rb, locales], не знаю пока, получится ли. Пока остановился на full, а не  mountable engine, т.к. требуется не отдельное пространство имен, а общее. Я ведь не собираюсь публиковать gem, а так будет меньше возни и больше удобства. Engine будет на запакованным.

Сдался на brainbench по ruby 1.9 Итог > 3.4 или лучше чем 72% сдававших

  •  
4.0 из 1 гол.
December 02, 2013 17:240 коммент.

Сдавал без подготовки - на шару 

Что приятно, Россия делает Украину и по максимальному и по минимальному результату

США похоже положили на Brainbench

 

Топы для России, Украины и США

Статистика по разбиению диска в ubuntu или как спланировать разделы диска для ubuntu

  •  
October 22, 2013 11:061 коммент.

В крайний раз я установил ubuntu 30 января 2011 года и с тех пор не трогал таблицу разделов (уже более 2,5 лет).

/home > ll /var/log/installer
итого 1,3M
drwxr-xr-x  3 root root 4,0K 2011-01-30 02:03 ./
drwxr-xr-x 33 root root  12K 2013-10-22 10:38 ../
drwxr-xr-x  2 root root 4,0K 2011-01-30 02:03 cdebconf/
-rw-r--r--  1 root root  17K 2011-01-30 02:03 hardware-summary
-rw-r--r--  1 root root 136K 2011-01-30 02:03 initial-status.gz
-rw-r--r--  1 root root  102 2011-01-30 02:03 lsb-release
-rw-------  1 root root 774K 2011-01-30 02:03 partman
-rw-r--r--  1 root root  56K 2011-01-30 02:03 status
-rw-------  1 root root 298K 2011-01-30 02:03 syslog

Стех пор я интенсивно ставил пакеты, некоторые сносил, и в итоге наполнение моих разделов выглядит так:

/home > df
Filesystems            Разм  Исп  Дост  Исп% смонтирована на
/dev/sdb1              20G   15G  3,9G  80% /
/dev/sdb2              20G  6,5G   13G  35% /home
/dev/sda9             693G  256G  402G  39% /data
/dev/sda11            158G   19G  131G  13% /backup

/home > mount|grep -v tmpfs|grep -v none|grep -v proc
/dev/sdb1 on / type ext4 (rw,noatime,nodiratime,relatime,discard,errors=remount-ro)
/dev/sdb2 on /home type ext4 (rw,nosuid,nodev,noatime,nodiratime,relatime,user_xattr)
/dev/sda9 on /data type ext4 (rw,nodev,noatime)
/dev/sda11 on /backup type ext4 (rw,nosuid,nodev,noatime)

Как видно, у меня в системе два диска:

  • один системный sdb - 2.5" SSD 60Gb
  • один для данных sda - обычный 3.5" 7200 терабайтник для данных.

Все фотки, видео, образы дисков, и т.п. лежат на /data, бекапы на /backups. Поэтому оставшиеся на системном диске пакеты относительно стабильны в размере.

Сейчас собираюсь ставить на новый ноут 64 битную ubuntu 12.04 в дуал буте с установленной win8. Поэтому увеличу размер корневого раздела / до 25Gb и уменьшу раздел /home до 15Gb

 

Сейчас в ноуте стоит обычный тормозной ноутбучный 5200 терабайтник. Под Винду на нем оставил 160Gb для игр и сред разработки. На нем создам опять разделы убунты 40Gb и отдельный раздел /data. Бэкапить буду на сервер.

Потом планирую поставить в нотик 256Gb быстрый SSD и тупо скопировать на него все разделы винды 160+ Gb (их там несколько) и оба раздела убунты общим размером в 40Gb.

 

Главный вывод: Если класть  данные на отдельный раздел, то 40Gb для убунты хватает с запасом! Поэтому можно ставить для системы очень доступные теперь мелкие SSD диски, под которыми линь  летает просто как МИГ-29

Вот как-то так. Удачи!

Немного офтопа: если убунта перестала засыпать

  •  
July 22, 2013 19:400 коммент.

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

Как только это приключилось, надо заглянуть в лог /var/log/pm-suspend.log и посмотреть что же там в конце после сообщения Running hooks for hibernate

А там выделенный мной красным виновник - недобиток /etc/pm/sleep.d/50upsmon из пакета nut, оставшийся после удаления этого пакета. Команда sudo rm /etc/pm/sleep.d/50upsmon привела убунту к нормальному сну. Надеюсь пригодится.

Initial commandline parameters: --quirk-dpms-suspend
--quirk-dpms-on
--quirk-vbestate-restore
--quirk-vbemode-restore
--quirk-vga-mode3
--quirk-vbe-post
Sat Jul  6 00:05:14 MSK 2013: Running hooks for hibernate.
/usr/lib/pm-utils/sleep.d/000kernel-change hibernate hibernate:success.
/usr/lib/pm-utils/sleep.d/00logging hibernate hibernate:Linux Durablis 2.6.32-45-generic #104-Ubuntu SMP Tue Feb 19 21:21:41 UTC 2013 i686 GNU/Linux
Module                  Size  Used by
ndiswrapper           184709  0
ipt_MASQUERADE          1407  0
xt_DSCP                 1677  0
ppdev                   5259  0
parport_pc             25962  0
iptable_nat             4414  0
iptable_mangle          2771  0
ipt_REJECT              1928  1
ipt_LOG                 4542  8
xt_limit                1382  8
xt_tcpudp               2011  55
ipt_addrtype            1631  0
xt_state                1098  6
it87                   17580  0
hwmon_vid               2298  1 it87
coretemp                4417  0
option                 20230  0
snd_hda_codec_realtek   203472  1
snd_hda_intel          22069  3
snd_hda_codec          74297  2 snd_hda_codec_realtek,snd_hda_intel
snd_hwdep               5412  1 snd_hda_codec
snd_pcm_oss            35308  0
snd_mixer_oss          13746  1 snd_pcm_oss
snd_pcm                70694  3 snd_hda_intel,snd_hda_codec,snd_pcm_oss
ip6table_filter         2343  1
snd_seq_dummy           1338  0
ip6_tables             11227  1 ip6table_filter
snd_seq_oss            26722  0
nf_nat_irc              1124  0
snd_seq_midi            4557  0
nf_conntrack_irc        3332  1 nf_nat_irc
fbcon                  35102  71
tileblit                1999  1 fbcon
nf_nat_ftp              1836  0
font                    7557  1 fbcon
bitblit                 4707  1 fbcon
softcursor              1189  1 bitblit
snd_rawmidi            19056  1 snd_seq_midi
nf_nat                 15735  4 ipt_MASQUERADE,iptable_nat,nf_nat_irc,nf_nat_ftp
vga16fb                11385  0
vgastate                8961  1 vga16fb
snd_seq_midi_event      6003  2 snd_seq_oss,snd_seq_midi
nf_conntrack_ipv4      10672  9 iptable_nat,nf_nat
nf_defrag_ipv4          1073  1 nf_conntrack_ipv4
nf_conntrack_ftp        5381  1 nf_nat_ftp
nf_conntrack           61615  9 ipt_MASQUERADE,iptable_nat,xt_state,nf_nat_irc,nf_conntrack_irc,nf_nat_ftp,nf_nat,nf_conntrack_ipv4,nf_conntrack_ftp
snd_seq                47263  6 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_seq_midi_event
iptable_filter          2271  1
snd_timer              19130  2 snd_pcm,snd_seq
snd_seq_device          5700  5 snd_seq_dummy,snd_seq_oss,snd_seq_midi,snd_rawmidi,snd_seq
ip_tables               9991  3 iptable_nat,iptable_mangle,iptable_filter
x_tables               14299  11 ipt_MASQUERADE,xt_DSCP,iptable_nat,ipt_REJECT,ipt_LOG,xt_limit,xt_tcpudp,ipt_addrtype,xt_state,ip6_tables,ip_tables
snd                    54244  18 snd_hda_codec_realtek,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_pcm_oss,snd_mixer_oss,snd_pcm,snd_seq_oss,snd_rawmidi,snd_seq,snd_timer,snd_seq_device
usbserial              33694  1 option
i915                  290772  2
drm_kms_helper         29329  1 i915
joydev                  8740  0
drm                   163779  3 i915,drm_kms_helper
i2c_algo_bit            5028  1 i915
intel_agp              24375  2 i915
soundcore               6620  1 snd
psmouse                63677  0
serio_raw               3978  0
lp                      7060  0
video                  17375  1 i915
output                  1871  1 video
snd_page_alloc          7076  2 snd_hda_intel,snd_pcm
agpgart                31724  2 drm,intel_agp
parport                32635  3 ppdev,parport_pc,lp
usbhid                 36110  0
hid                    67288  1 usbhid
             total       used       free     shared    buffers     cached
Mem:       2052676    1987652      65024          0     100972     643128
-/+ buffers/cache:    1243552     809124
Swap:            0          0          0
success.
/usr/lib/pm-utils/sleep.d/00powersave hibernate hibernate:success.
/usr/lib/pm-utils/sleep.d/01PulseAudio hibernate hibernate:success.
/etc/pm/sleep.d/10_grub-common hibernate hibernate:success.
/etc/pm/sleep.d/10_unattended-upgrades-hibernate hibernate hibernate:success.
/usr/lib/pm-utils/sleep.d/49bluetooth hibernate hibernate:not applicable.
/etc/pm/sleep.d/50upsmon hibernate hibernate:“Stopping UPS monitor”
ups-monitor: unrecognized service
Returned exit code 1.
Sat Jul  6 00:05:17 MSK 2013: Inhibit found, will not perform hibernate
Sat Jul  6 00:05:17 MSK 2013: Running hooks for thaw
/usr/lib/pm-utils/sleep.d/49bluetooth thaw hibernate:not applicable.
/etc/pm/sleep.d/10_unattended-upgrades-hibernate thaw hibernate:success.
/etc/pm/sleep.d/10_grub-common thaw hibernate:success.
/usr/lib/pm-utils/sleep.d/01PulseAudio thaw hibernate:success.
/usr/lib/pm-utils/sleep.d/00powersave thaw hibernate:success.
/usr/lib/pm-utils/sleep.d/00logging thaw hibernate:success.
/usr/lib/pm-utils/sleep.d/000kernel-change thaw hibernate:success.

Как просто создать множество AJAX форм на одной странице для реализации редактирования на месте (in place editing)

  •  
February 22, 2013 08:320 коммент.

Бывают задачи, когда пользователю надо  иметь все объекты модели перед глазами и тут же редактировать любой из них. Хороший пример - параметры иконок эмоций (emoticons). Пользователь должен видеть изображение иконки, чтобы установить для нее код :-$ и имя (сомнение), включить или выключить иконку. При этом ему надо видеть, какие коды и названия уже использованы, и желательно, чтобы переход от одной иконки к другой не требовал от пользователя многих телодвижений.

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

 

emoticons admin page fragment

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

 

Каждая иконка с двумя полями ввода для кода и названия т выключателем - суть формы, которые срабатывают на событие onChange. Стоит ввести значение и нажать или или кликнуть мышой в другое поле, как введенное значение сохраняется.

 

Ниже я опишу, как просто создать эту страницу. 

 

Во-первых, иконка это обычный ресурс, допускающий два экшена - index и update.

resources :emoticons, :only => [:index, :update]

 

 

Во-вторых, иконки имеют тривиальный контроллер:

 

class Admin::Settings::EmoticonsController< Admin::Settings::BaseController

  def index
    @emoticons = Emoticon.all
  end

  def update
    @emoticon= Emoticon.find params[:id]
    if @emoticon.update_attributes params[:emoticon]
      render :text => "success" # это нужно только для отладки
    else
      render :text => "error"
    end
  end

end

 

и не менее тривиальное представление:

index.html.haml

 

.page-header

  %h3= t(".title")

.emoticons

  - @emoticons.each do |e|

    = render "emoticon", :e => e

 

 

_emoticon.html.haml 

Обратите внимание, форма - самая обычная, даже без :remote => true и не имеет кнопок.

 
.emoticon.prop{:id => e.id}
  =form_for e, :url => admin_settings_emoticon_path(e), :class => "emoticon" do |f|
    %ul  
      %li= image_tag(e.url)
      %li= e.position
      %li.filename= e.filename
      %li= f.check_box  :enabled, :class => "attr"
      %li= f.text_field :code,    :class => "attr code"
      %li= f.text_field :name,    :class => "attr name"
 
 
 
А суть вот в чем
 
Все дело в AJAX коде. Надо найти все формы и установить один общий обработчик события onChange. А в обработчике предусмотреть поиск формы, поле которой получило событие.
 
 
$("document").ready(function(){
 
  // обработчик изменения значения в полях форм иконок эмоций
  var onChange = function(eventObject) {
      // найти форму в которой находится поле ввода, т.к. форм over 9000
      var f = $(eventObject.target).closest('form');
      $.ajax({
        type: "POST",
        url:  f.attr('action'),
        data: f.serialize()
      })
    };

 
  // Установка обработчиков на все поля всех форм
  $("form.edit_emoticon").each(function(index, form){
    $(form).find('input.attr').change(onChange);
    });
 
});
 
Удачи!!!