rails3: link_to + image_tag
было: (rails 2.x)
1 2 3 |
<%= link_to image_tag('rainbow.png'), '/' -%>
<%= link_to "#{image_tag('rainbow.png')}Главная", '/' -%>
|
стало: (rails 3.x)
1 2 3 |
<%= link_to image_tag('rainbow.png'), '/' -%>
<%= link_to "#{image_tag('rainbow.png')}Главная".html_safe, '/' -%>
|
Первый вариант (просто image_tag) не изменился, а вот второй вариант (image_tag внутри строки) теперь требует явного указания html_safe.
rails3: link_to_function
1 |
ActionView::Template::Error (undefined method `link_to_function' for #<Class>) |
теперь link_to_function находится в плагине prototype_legacy_helper:
1 |
./script/rails plugin install git://github.com/rails/prototype_legacy_helper.git |
возможно, ребята придумали чем-то заменить, а потом и задепрекейтить, но никаких постов на эту тему я в нете не нашел.
rspec bisect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#./rspec-bisect.rb spec/**/*_spec.rb spec/controllers/spaces/tickets_controller_spec.rb [.] rspec runner: ./script/spec [.] target spec : spec/controllers/spaces/tickets_controller_spec.rb [.] 123 candidate specs [.] running 62 specs.. Done. ( 19s) (105/0/4) : target OK [.] running 63 specs.. Done. ( 64s) (386/2/6) : target FAIL [.] running 32 specs.. Done. ( 34s) (157/0/2) : target OK [.] running 32 specs.. Done. ( 43s) (238/2/4) : target FAIL [.] running 16 specs.. Done. ( 38s) (129/2/1) : target FAIL [.] running 8 specs.. Done. ( 27s) (73/0) : target OK [.] running 9 specs.. Done. ( 19s) (65/2/1) : target FAIL [.] running 5 specs.. Done. ( 19s) (52/2/1) : target FAIL [.] running 3 specs.. Done. ( 16s) (33/0) : target OK [.] running 3 specs.. Done. ( 18s) (28/2/1) : target FAIL [.] running 2 specs.. Done. ( 17s) (27/2/1) : target FAIL [*] found matching spec: spec/models/mailman_spec.rb |
Download here.
Rails 3.x "Crazy Loading" is awesome!
1 2 3 4 5 6 7 8 |
red_items = Item.where(:colour => 'red') red_items.find(1) item = red_items.new item.colour #=> 'red' red_items.exists? #=> true red_items.update_all :colour => 'black' red_items.exists? #=> false |
// actually it’s “Lazy Loading” and stuff. Read more: Active Record Query Interface 3.0.
Rails streaming VS mongrel, thin, ebb and Passenger
С некоторых пор моим любимым веб-сервером для руби приложений является thin.
Но сегодня он меня конкретно разочаровал. Как, впрочем и mongrel.
Как нетрудно догадаться из заголовка, дело касается streaming
(про стриминг в рельсах читать тут, начиная с Streaming data and/or controlling the page generation)
(и почему они не автогенерят id для хидеров?? можно было бы ссылку сразу куда надо поставить..)
пример там приведен такой:
1 2 3 4 5 6 7 |
# Streams about 180 MB of generated data to the browser. render :text => proc { |response, output| 10_000_000.times do |i| output.write("This is line #{i}\n") output.flush end } |
так вот, что thin, что mongrel, оба тупо забивают на этот стриминг, и пытаются всосать в себя всё что им рельсы отдают, а потом выплюнуть юзеру единым куском..
thin, например, делает так:
1 2 |
terminate called after throwing an instance of 'std::runtime_error' what(): no allocation for outbound data |
а mongrel так:
1 2 |
Error calling Dispatcher.dispatch #<NoMemoryError: failed to allocate memory> /usr/lib64/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/cgi_process.rb:58:in `write' |
Еще хотел быстренько попробовать ebb, но не обнаружил в дистрибутиве внятных инструкций по его установке и настройке.. ладно, запустил через Ebb.start_server("/path/to/rails/app"), но толку от этого оказалось мало – на порту он поднялся, но ни на один запрос отвечать не захотел.. тупо висел и думал о чем-то там своем..
And the winner is…
Passenger. Хоть я его раньше и не использовал, и довольно таки скептически к нему относился, но он успешно зарекомендовал себя в продакшене, легко поставился (потянув, естественно за собой апача, которого я тоже недолюбливаю..) (хмм.. хотя он есть и для nginx, это несколько меняет дело, на досуге поковыряю)
Так вот, Passenger легко отдал псевдофайлик размером 2 гига с локалхоста на локалхост со скоростью около 12 мегабайт в секунду. При этом не показав никакого значительного увеличения потребления памяти!
PS:
Linux zz 2.6.31-gentoo-r6-zz #1 SMP PREEMPT Tue Dec 22 01:38:46 YEKT 2009 x86_64 Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz GenuineIntel GNU/LinuxRails 2.3.5mongrel 1.1.5thin 1.2.5passenger 2.2.9
You MUST free memory you got from ALLOC_N & friends
It’s not documented anywhere, but you must call “xfree()” (note ‘x’ there) on memory blocks you got from ALLOC_N & friends.
Ruby will not free that memory automatically during it’s usual GC process.
Guys from ruby-talk and rubyforge also noticed that.
sample code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
VALUE method_parse(VALUE self, VALUE text) {
VALUE s;
char *p = RSTRING(text)->ptr;
in_buf_len = RSTRING(text)->len;
// [skipped some code here]
buf = ALLOC_N(char, bufsize);
// protect buf from GC (theoretically)
rb_iv_set(self,"@obj",Data_Wrap_Struct(rb_cData,NULL,NULL,buf));
// [skipped some hard work here]
// make ruby string from our char[] data
s = rb_str_new(buf,bufptr-buf);
// cleanup
rb_iv_set(self,"@obj",Qnil);
xfree(buf);
buf = NULL;
bufsize = 0;
return s;
}
|
benchmark: Ruby's rb_str_cat() vs C's strcat()
В связи с началом написания расширений для ruby решил провести бенчмарк рубевской функции rb_str_cat() VS сишной родной strcat()
Результат меня немало удивил:
1 2 |
strcat 3.360s rb_str_cat 0.002s |
Тесты проводились в тяжелых полевых условиях – испытуемым надо было 100000 (сто тысяч) раз приклеить к строке(изначально пустой) один заранее заданный символ.
И ruby сделал это, грубо говоря, в 1500 раз быстрее!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#define N 100000 VALUE test_concat_rb_str_cat(VALUE self){ int i; VALUE s = rb_str_new2(""); for(i=0;i<N;i++) rb_str_cat(s,"t",1); return s; } VALUE test_concat_strcat(VALUE self){ int i; char buf[N+2]; *buf=0; for(i=0;i<N;i++) strcat(buf,"t"); return rb_str_new2(buf); } |
На самом деле никакого подвоха тут нет – просто в руби объект “строка” содержит в себе не только указатель на байты содержимого, но и длину строки тоже, а сишный вариант при этом каждый раз считает длину строки. Т.е. ему, бедному, пришлось перемолотить при этом суммарно почти 5 гигабайт, каждый раз считая длину строки начиная с самого первого символа, и до 100-тысячного в конце.
Прелесть руби здесь в том что не надо думать о памяти – он сам выделит сколько надо и освободит когда будет можно. В сях это слегка сложнее, но можно доработать сишный код так, чтобы он и память выделял динамически, и длину строки стопицот раз не пересчитывал. Например, так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
VALUE test_concat_char(VALUE self){
int i;
int bufsize = 0x1000;
char *buf = malloc(bufsize);
char *p=buf;
VALUE s;
for(i=0;i<N;i++){
*p++ = 't';
if( p-buf >= bufsize ){
char *oldbuf = buf;
bufsize += 0x1000;
buf = realloc(buf, bufsize);
p = buf + (p-oldbuf);
}
}
s=rb_str_new(buf,p-buf);
free(buf);
return s;
}
|
Скорость обработки получается уже совсем другая:
1 2 3 |
strcat 3.36732s rb_str_cat 0.00215s char 0.00013s |
Вот теперь сишный код в 16 раз быстрее чем руби, и в 24000 с лишним раз быстрее, чем в начале.
PS: это всё на Linux 2.6.31-gentoo-r6-zz x86_64 Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz
пишем на C расширение для ruby
Это не просто, а очень просто (как два пальца об асфальт два файла написать):
1й файл: mytest.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "ruby.h" void Init_mytest(); VALUE method_sayhello(VALUE); VALUE mytest = Qnil; void Init_mytest() { mytest = rb_define_module("MyTest"); rb_define_method(mytest, "sayhello", method_sayhello, 0); } VALUE method_sayhello(VALUE self) { puts("Hello World!"); return Qnil; } |
2й файл: extconf.rb
1 2 3 4 |
require 'mkmf' extension_name = 'mytest' dir_config(extension_name) create_makefile(extension_name) |
запуск:
1 2 3 4 5 6 7 8 9 10 11 12 |
#ruby extconf.rb creating Makefile #make x86_64-pc-linux-gnu-gcc -shared -o mytest.so mytest.o -L. -L/usr/lib64 -Wl,-R/usr/lib64 -L. -Wl,-O1 -rdynamic -Wl,-export-dynamic -Wl,-R -Wl,/usr/lib64 -L/usr/lib64 -lruby18 -lpthread -lrt -ldl -lcrypt -lm -lc #irb irb(main):001:0> require 'mytest' => true irb(main):002:0> include MyTest => Object irb(main):003:0> sayhello Hello World! => nil |
// пример содран с Введения в расширения Ruby на C, но там всё разжевывается под винду и вижуалстудию
спамеры научились подбирать SASL пароли
Что-то стал почтовик туго работать..
Смотрю – loadavg около 3.8 .. что-то тут неладно..
Смотрю tail -f /var/log/maillog – там жуть полнейшая.. всё скачет и мелькает сотнями строк в секунду..
Причем чаще всего строчки вида:
host mailin-03.mx.aol.com[205.188.109.56] refused to talk to me: 554 IP:y.y.y.y – A problem occurred. (Ask your postmaster for help or to contact tosa@rx.t-online.de to clarify.)
или такие:
host c.mx.mail.yahoo.com[209.191.88.254] refused to talk to me: 421 4.7.1 [TS03] All messages from y.y.y.y will be permanently deferred; Retrying will NOT succeed. See http://postmaster.yahoo.com/421-ts03.html
или такие:
status=bounced (host mxs.mail.ru[94.100.176.20] said: 550 spam message discarded. Please visit http://mail.ru/notspam/ or report details to abuse@corp.mail.ru. Error code: 0F9B7FC84BF25CB6A821A57C9B6112E28F9CA260D04BD65B (in reply to end of DATA command))
в /var/spool/postfix – 180тыс сообщений.. O_o
В итоге оказалось что спамеры подобрали пароль на акк вида test:test (явно кто-то из админов заводил для теста..) и вовсю спамили с него везде куда их черная душа пожелала..
В сухом остатке:
- сменил пароль юзера на непотребство вида “gbplf[eq” :)
- жестко забанил спамеров:
1 2 3 4 |
ipfw table 10 add 82.127.122.36 ipfw table 10 add 203.161.99.96 ipfw table 10 add 165.228.2.249 ipfw add deny ip from "table(10)" to me |
- ограничил количество одновременных SMTP-коннектов 5-ю штуками:
1 |
ipfw add allow ip from any to me 25 setup limit src-addr 5 |
- запустил чистилку на /var/spool/postfix:
1 2 |
cd /var/spool/postfix grep -rlF "sender: test" . | xargs -L 100 rm |
работает небыстро, зато надежно :) уже вычистила около 30K сообщений.
ключик “-L 100” нужен для того чтобы rm вызывался не в самом-самом конце поиска, а на каждые N найденных файлов.
инвайты на google wave
Раздам инвайты на google wave.
Есть 8 штук.
Вдруг еще у кого нет :)
халява: ifolder.ru OR last.fm OR скайп
отдам бесплатно в хорошие руки:
- пополнение баланса скайп на что-то около 150руб
- оплаченный акк на ifolder.ru
- оплаченный акк на last.fm
ОДНО из трех! а если точнее – то это был такой мелкий приз на newburn.ru, ну и мне собсно ни то ни то ни то не особо и надо..
так что отдам бесплатно :)
upd: халява закончилась кто не успел – тот опоздал
ng_sbinat – (Symmetric | Simple) Bidirectional NAT
1. что это?
это такой простой двусторонний нат.
работает в ядре freebsd, внутри нетграфа.
вешается непосредственно на ng_ether интерфейс (напр. em0)
2. для чего это?
для трансляции одной /16 сетки в другую (например 192.168.×.y <—> 10.22.×.y)
3. требования?
- freebsd >= 7.0
- netgraph
- сорцы ядра
- прямые руки :)
4. где взять / more info ?
как установить ДубльГис на Gentoo
1 2 3 4 5 |
emerge -tva layman autounmask echo "source /usr/local/portage/layman/make.conf" >> /etc/make.conf layman -a sunrise autounmask -n app-misc/2gis-data-2009.12 USE="kur chel ekb" emerge -tva 2gis |
перед последним шагом в USE указать те города, которые хотим ставить.
текущие поддерживаемые:
kur astr barn biysk chel ekb irk kaz kem kras nkuz nnov nsk nvar odes omsk perm sam tim tom ufa
mc: подсчет размера каталогов
“Вообще-то в MC всю жизнь для подсчёта размеров каталогов было сочетание ctrl-space”
спасибо анонимусу отсюда :)