Архив рубрики: rails

Rails preload, eager_load, includes и joins.

http://habrahabr.ru/post/191762/

http://sqlfiddle.com/#!2/659f69/1

Rails предоставляют нам 4 различных способа загрузки ассоциаций: preload, eager_load, includes и joins. Рассмотрим каждый из них:

Preload


Этот метод загружает ассоциации в отдельном запросе:

User.preload(:posts).to_a

# =>
SELECT "users".* FROM "users"
SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (1)


Т.к. preload всегда создает два отдельных запроса, то мы не можем использовать таблицу posts в условии выборки:

User.preload(:posts).where("posts.desc='ruby is awesome'")

# =>
SQLite3::SQLException: no such column: posts.desc:
SELECT "users".* FROM "users"  WHERE (posts.desc='ruby is awesome')


А таблицу users – можем:

User.preload(:posts).where("users.name='Neeraj'")

# =>
SELECT "users".* FROM "users"  WHERE (users.name='Neeraj')
SELECT "posts".* FROM "posts"  WHERE "posts"."user_id" IN (3)




Includes


По умолчанию includes действует точно так же, как и preload, но в случае наличия условия по ассоциированной таблице переключается на создание единственного запроса с LEFT OUTER JOIN.

User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
       "posts"."title" AS t1_r1,
       "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE (posts.desc = "ruby is awesome")


Если по каким-то причинам необходимо форсировать применение такого подхода, то можно использовать метод references:

User.includes(:posts).references(:posts).to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
       "posts"."title" AS t1_r1,
       "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"



Eager_load


Этот метод загружает ассоциации в одном запросе с использованием Left Outer Join, точно так же, как действует includes в сочетании с references.

User.eager_load(:posts).to_a

# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
       "posts"."title" AS t1_r1, "posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"



Joins


Создает запрос с использованием INNER JOIN. 

User.joins(:posts)

# =>
SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"


При этом, загружаются данные только из таблицы users. Кроме того, этот запрос может возвратить дублирующие друг друга записи:

def self.setup
  User.delete_all
  Post.delete_all

  u = User.create name: 'Neeraj'
  u.posts.create! title: 'ruby', desc: 'ruby is awesome'
  u.posts.create! title: 'rails', desc: 'rails is awesome'
  u.posts.create! title: 'JavaScript', desc: 'JavaScript is awesome'

  u = User.create name: 'Neil'
  u.posts.create! title: 'JavaScript', desc: 'Javascript is awesome'

  u = User.create name: 'Trisha'
end



Результат выполнения User.joins(:posts) в БД с такими данными:

#<User id: 9, name: "Neeraj">
#<User id: 9, name: "Neeraj">
#<User id: 9, name: "Neeraj">
#<User id: 10, name: "Neil">


Избежать повторений мы можем с использованием distinct:

User.joins(:posts).select('distinct users.*').to_a
# в комментариях подсказывают, что можно сделать проще:
User.joins(:posts).uniq


Если же мы хотим дополнительно получить какие-либо данные из таблицы posts, мы должны внести их в предложение select:

records = User.joins(:posts).select('distinct users.*, posts.title as posts_title').to_a
records.each do |user|
  puts user.name
  puts user.posts_title
end


Стоит заметить, что после выполнения метода joins вызов user.posts приведет в созданию еще одного запроса.

Методы eager нужны, чтобы избежать появления так называемых запросов N+1, и не стоит их использовать для подключения ассоциаций в where и order, для этого есть joins. Рекомендую гем bullet (https://github.com/flyerhzm/bullet), чтобы найти запросы в которых нужна eager-загрузка.

Плохо, когда появляются похожие штуки: ‘posts’.’user_id’ AS t1_r2, ‘posts’.’desc’ AS t1_r3, этим грешит includes особенно при сортировке через ассоциацию, даже если она подключена через joins (вроде в 4 исправили). И во многих случаях to_a не актуально.

Алсо, гем squeel (https://github.com/ernie/squeel) очень упрощает написание сложных запросов.

Подключаем DateTimePicker

link1    link2    link3    link3

Первый способ(простой DateTimePicker)

Необходимые гемы:

1
2
3
4
  gem 'rails-assets-moment'
  gem 'rails-assets-datetimepicker'
end

Подключаем css:

1
*= require datetimepicker

Подключаем js:

1
2
//= require moment
//= require datetimepicker

Инициализация(coffee):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# DateTimePicker ОПИСАНИЕ ВСЕХ ОПЦИЙ:
#
###############################################
# Дата и время
$('.datetimepicker').datetimepicker
  format: 'd.m.Y H:i'
  pick12HourFormat: false
  step: 60
  lang: 'ru'
  # inline: true #показать виджет сразу и не скрывать
# Дата
$('.datepicker').datetimepicker
  timepicker:false,
  format: 'Y-m-d'
  lang: 'ru'
###############################################

Поле для даты(haml):

1
%input.datetimepicker{ name:"date", value: DateTime.now.strftime('%d.%m.%Y %H:%M') }

Второй способ способ(Bootstrap)

Используем гем datetimepicker-rails

Необходимые гемы:

1
2
gem 'momentjs-rails'
gem 'datetimepicker-rails', github: 'zpaulovics/datetimepicker-rails', branch: 'master', submodules: true #Bootstrap 3+

Подключаем js:

1
2
3
//= require moment
//= require bootstrap-datetimepicker
//= require pickers

Подключаем css:

1
*= require bootstrap-datetimepicker

Выполняем в терминале:

1
rails generate datetimepicker_rails:install

Использование в SimpleForm (haml):

1
2
3
= f.input :start_date_time, :as => :datetime_picker
= f.input :closing_date, :as => :date_picker

 

debug

http://rusrails.ru/debugging-rails-applications

-Rails.logger.info «H1ello world! #{@version.title}»
- byebug

help list

чтобы просмотреть предыдущие десять строчек, следует написать list- (or l-)

В любое время можете вызвать команду backtrace (или ее псевдоним where), чтобы напечатать трассировку приложения

команду frame _n_, где n это номер определенного фрейма

instance_variables

instance_variables.include? «@articles»

(byebug) help var
v[ar] cl[ass]                   show class variables of self
v[ar] const <object>            show constants of object
v[ar] g[lobal]                  show global variables
v[ar] i[nstance] <object>       show instance variables of object
v[ar] l[ocal]                   show local variables

 var instance Article.new

display @articles

 Чтобы остановить отображение переменной, используйте undisplay _n_, где n это номер переменной (1 в последнем примере)

Используйте step (сокращенно s) для продолжения запуска вашей программы до следующей логической точки останова и возврата контроля debugger.

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

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

Можете добавлять точки останова динамически с помощью команды break (или просто b). Имеются 3 возможных способа ручного добавления точек останова:

  • break line: устанавливает точку останова в строчке номер line в текущем файле исходника.
  • break file:line [if expression]: устанавливает точку останова в строчке номер line в файле file. Если задано выражение expression, оно должно быть вычислено в true, чтобы запустить отладчик.
  • break class(.|\#)method [if expression]: устанавливает точку останова в методе method (. # для метода класса и экземпляра соответственно), определенного в классе class. Выражение expression работает так же, как и с file:line.
  • Используйте info breakpoints _n_ или info break _n_ для отображения перечня точек останова
  • Чтобы удалить точки останова: используйте команду delete _n_ для устранения точки останова номер n.

Также можно включить или отключить точки останова:

  • enable breakpoints: позволяет перечню breakpoints или всем им, если перечень не определен, останавливать вашу программу. Это состояние по умолчанию для создаваемых точек останова.
  • disable breakpointsbreakpoints не будут влиять на вашу программу.

Команда catch exception-name (или просто cat exception-name) может использоваться для перехвата исключения типа exception-name

Есть два способа возобновления выполнения приложения, которое было остановлено отладчиком:

  • continue line-specification: возобновляет выполнение программы с адреса, где ваш скрипт был последний раз остановлен; любые точки останова, установленные на этом адресе будут пропущены. Дополнительный аргумент line-specification позволяет вам определить число линий для установки одноразовой точки останова, которая удаляется после того, как эта точка будет достигнута.
  • finish frame-number: выполняет, пока не возвратится выделенный кадр стека. Если номер кадра не задан, приложение будет запущено пока не возвратиться текущий выделенный кадр. Текущий выделенный кадр начинается от самых последних, или с 0, если позиционирование кадров (т.е. up, down или frame) не было выполнено. Если задан номер кадра, будет выполняться, пока не вернется указанный кадр

Две команды позволяют открыть код из отладчика в редакторе:

  • edit [file:line]: редактирует файл file, используя редактор, определенный переменной среды EDITOR. Определенная линия line также может быть задана

Чтобы выйти из отладчика, используйте команду quit (сокращенно q), или ее псевдоним exit

У byebug имеется несколько доступных опций для настройки его поведения:

  • set autoreload: Перезагрузить исходный код при изменении (по умолчанию true).
  • set autolist: Запускать команду list на каждой точке останова (по умолчанию true).
  • set listsize _n_: Установить количество строчек кода для отображения по умолчанию n (по умолчанию 10).
  • set forcestep: Убеждаться, что команды next и step всегда переходят на новую строчку.

Можно просмотреть полный перечень, используя help set. Используйте help set _subcommand_ для изучения определенной команды set.

.byebugrc в домашней директории

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

  • Footnotes: У каждой страницы Rails есть сноска, дающая информацию о запросе и ссылку на исходный код через TextMate.
  • Query Trace: Добавляет трассировку запросов в ваши логи.
  • Query Reviewer: Этот плагин rails не только запускает «EXPLAIN» перед каждым из ваших запросов select в development, но и представляет небольшой DIV в отрендеренном результате каждой страницы со сводкой предупреждений по каждому проанализированному запросу.
  • Exception Notifier: Предоставляет объект рассыльщика и набор шаблонов по умолчанию для отправки уведомлений по email, когда происходят ошибки в приложении в Rails.
  • Better Errors Заменяет стандартную страницу ошибки Rails новой, содержащей больше контекстной информации, такой как исходный код и просмотр переменных.
  • RailsPanel Расширение для Chrome для разработки на Rails, которое подхватывает изменения в development.log. Всю информацию о запросах к приложинеию Rails можно смотреть в браузере, в панели Developer Tools. Предоставляет обзор времени db/rendering/total, списка параметров, отрендеренных вьюх и так далее.

about rvm

1. Установка RVM


1. Для установки вам понадобятся curl и git (apt-get install git curl)
2.

    #Скачивание скрипта установки с сервера и запуск (от имени вашего пользователя)
     % bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
    


3. После установки нужно добавить информацию об установленном приложении rvm в bash
#Дописывает в конфигурационный файл bash строчку, которая проверяет наличие директории с rvm и если
#всё ок, запускает программу
% echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function'>>~/.bash_profile

В файле $HOME/.bashrc заменяем строчку [ -z "$PS1" ] && return на if [[ -n "$PS1" ]]; then Т.к. мы используем if, то в конце файла проставьте fi, это позволяет запускать программы в неинтерактивном режиме, а rvm как раз является примером такой программы
4. Проверяем как прошла установка 
% rvm -v 
rvm 1.6.20 by Wayne E. Seguin (wayneeseguin@gmail.com) [https://rvm.beginrescueend.com/]
если вы видите версию rvm, значит всё ОК 


2. Работа с разными версиями Ruby


Чтобы просмотреть все доступные для установки версии Ruby 
% rvm list known
# MRI Rubies
[ruby-]1.8.6[-p420]
[ruby-]1.8.6-head
[ruby-]1.8.7[-p334]
[ruby-]1.8.7-head
[ruby-]1.9.1-p378
[ruby-]1.9.1[-p431]
[ruby-]1.9.1-head
[ruby-]1.9.2[-p180]
[ruby-]1.9.2-head
ruby-head
# GoRuby
goruby
# JRuby
jruby-1.2.0
jruby-1.3.1
jruby-1.4.0
jruby-1.6.1
jruby[-1.6.2]
jruby-head

Предположим вы работаете с двумя версиями 1.8.7 для ROR2 и 1.9.2 для ROR3
# Устанавливаем 2 версии Ruby
% rvm install 1.8.7 
% rvm install 1.9.2 

Чтобы увидеть все установленные версии Ruby
% rvm list
rvm rubies
ruby-1.8.7-p334 [ i386 ]
ruby-1.9.2-p180 [ i386 ]

Переключиться на ruby 1.8.7
% rvm use ruby-1.8.7
Using /home/user/.rvm/gems/ruby-1.8.7-p334

Использовать версию ruby 1.9.2 по умолчанию
% rvm use ruby 1.9.2 --default
Using /home/user/.rvm/gems/ruby-1.9.2-p180
% rvm list
rvm rubies
=> ruby-1.9.2-p180 [ i386 ] # "=>" показывают версию Ruby установленную по умолчанию
ruby-1.8.7-p334 [ i386 ]


3. Работа с gemsets


Например вы используете Ruby On Rails версии 2 и 3 с Ruby 1.8.7 и для каждого из них у вас свой набор gem’s.
Создадим два разных набора gemset’ов:
% rvm use 1.8.7@rails2 --create
Using /home/user/.rvm/gems/ruby-1.8.7-p334 with gemset rails2
% rvm use 1.8.7@rails3 --create
Using /home/user/.rvm/gems/ruby-1.8.7-p334 with gemset rails3
% rvm gemset list
gemsets for ruby-1.8.7-p334 (found in /home/slip/.rvm/gems/ruby-1.8.7-p334)
global # gemset по умолчанию
rails2
rails3
% rvm use 1.8.7@rails3 --default # Использовать gemset rails3 по умолчанию
% rvm gemset list
gemsets for ruby 1.8.7-p334 (found in /home/user/.rvm/gems/ruby-1.8.7-p334)
global
rails2
=> rails3 # rails3 стоит по умолчанию

Gemset’ы можно удалять, очищать, экспортировать и импортировать гемы из одного в gemset’a в другой.
RVM предоставляет следующие команды для работы с gemsets:
create — создание нового gemset
export — экспорт списка гемов в файл default.gems
import — установка в текущий gemset списка гемов из файла default.gems
delete — удалить gemset
empty — очистить gemset

4. Задание окружения под отдельный проект с помощью .rvmrc


Как быть если у вас несколько проектов, каждый из которых используют разную версию gemset? Можно конечно переключиться между gemset’ами вручную с помощь rvm use {rubyversion}@{gemsetname}, но и тут RVM приходит нам на помощь, делая эту часть работы за нас. 
Создаем файл .rvmrc в корневой директории проекта. Например проект используют ruby версии 1.8.7 с gemset projectname.
#Содержимое файла .rvmrc
rvm use 1.8.7@projectname

Теперь когда вы заходите в директорию, cd /home/user/www/projectname — RVM исполняет команду из файла .rvmrc и вы видите на экране подобное сообщение
Using /home/user/.rvm/gems/ruby-1.8.7-p334 with gemset projectname

Таким образом вам больше не приходиться думать какой gemset использует конкретный проект и устанавливать его вручную.

5. Команды RVM которые могут оказаться полезными


1. Completion — позволяет использовать tab при работе с rvm 
Чтобы включить, добавьте строку [[ -r $rvm_path/scripts/completion ]] &&. $rvm_path/scripts/completionв файл .bashrc или .bash_profile, после строки с подлючением rvm. Подробнее можно почитать здесьrvm.beginrescueend.com/workflow/completion
2. rvmreset — перезагрузка RVM
3. rvm uninstall — удалить одну или несколько версию Ruby, оставив исходники
4. rvm implode — полностью удалить RVM (удаляет ВСЁ)

6. Шпаргалка по основным командам RVM


rvm list known — получить список всех версий ruby доступных для установки
rvm install 1.9.1 – установить ruby версии 1.9.1
rvm remove 1.9.2 – удалить ruby версии 1.9.2
rvm use 1.9.2 — переключиться на ruby версии 1.9.2
rvm use 1.9.2@rails3 —default — установить версию ruby 1.9.2 c gemset rails3 по умолчанию
rvm use system — использовать системную версию ruby
rvm list – список установленных версий ruby
rvm gemset list – список gemset’ов в выбранной версии ruby
rvm use 1.9.2@rails3 —create создать gemset rails3 для ruby версии 1.9.2
rvm gemset export — экспортировать гемсет в файл default.gems
rvm gemset import default.gems — установить gem’s из списка в файле defaults.gem в текущий gemset

Update rvm:

echo rvm_autoupdate_flag=2 >> ~/.rvmrc

gpg2 —keyserver hkp://keys.gnupg.net —recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

rvm list known

Cкриншот с видео при загрузке

before_save :define_screenshot
 
 def define_screenshot
    return if file.queued_for_write.empty?
    temp_name = get_temp_name
    video_file = file.queued_for_write[:original].path
    cmd = 'ffmpeg -i #{video_file} -an -ss 00:00:10 -an -r 1 -vframes 1 -y -f mjpeg #{temp_name} >/dev/null 2>&1'
    Rails.logger.info 'Running cmd: #{cmd}'
    system cmd
    self.thumbnail = File.open(temp_name)
  end

  def get_temp_name
    tempdir = Dir::tmpdir || /tmp
    t = Time.now.strftime('%Y%m%d')
    path = 'clip#{t}-#{$$}-#{rand(0x100000000).to_s(36)}.jpg'
    File.join(tempdir, path)
  end

restore record mongoid

 

include Mongoid::Paranoia

c = Contest.find(«541088a753bb5660ad00041e»)

claim = c.claims.where(deleted_at: { ‘$ne’ => nil }).last

claim.restore

c.claims.where(deleted_at: { ‘$ne’ => nil }).to_a

Migration

script/generate migration NAMEOFMIGRATION
export RAILS_ENV=production / set export RAILS_ENV=production
rake db:migrate

wkhtmltopdf & wkhtmltoimage

cd /tmp

http://wkhtmltopdf.org/obsolete-downloads.html

wget https://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.11.0_rc1-static-amd64.tar.bz2

tar xvjf wkhtmltopdf-0.11.0_rc1-static-amd64.tar.bz2

cp wkhtmltopdf-amd64 wkhtmltopdf

cp wkhtmltopdf /usr/local/bin/

wget https://wkhtmltopdf.googlecode.com/files/wkhtmltoimage-0.11.0_rc1-static-amd64.tar.bz2

tar xvjf wkhtmltoimage-0.11.0_rc1-static-amd64.tar.bz2

cp wkhtmltoimage-amd64 wkhtmltoimage

cp wkhtmltoimage /usr/local/bin/

cd /project

touch tmp/restart.txt

 

$ yum search 75dpi

maybe

xorg-x11-fonts-75dpi.noarch : A set of 75dpi resolution fonts for the X Window System.
xorg-x11-fonts-ISO8859-1-75dpi.noarch : A set of 75dpi ISO-8859-1 fonts for X.
xorg-x11-fonts-ISO8859-14-75dpi.noarch : ISO8859-14-75dpi fonts
xorg-x11-fonts-ISO8859-15-75dpi.noarch : ISO8859-15-75dpi fonts
xorg-x11-fonts-ISO8859-2-75dpi.noarch : A set of 75dpi Central European language fonts for X.
xorg-x11-fonts-ISO8859-9-75dpi.noarch : ISO8859-9-75dpi fonts

and then

$ sudo yum install xorg-x11-fonts-75dpi.noarch

https://stackoverflow.com/questions/5035601/error-running-wkhtmltopdf-error-while-loading-shared-libraries

$ sudo yum install libXrender libXext fontconfig
$ sudo yum installl xorg-x11-font-utils xorg-x11-fonts-Type1

Deprecation warning – Rails 2.3.8 + errors

Change in config/environment.rb :secret_ket into :key.:

1
2
3
4
config.action_controller.session = {
  :secret_key => 'aaaaa' ,
  :secret => 'tajneprzezpoufne'
}
1
2
3
4
config.action_controller.session = {
  :key => 'aaaaa' ,
  :secret => 'tajneprzezpoufne'
}

 

nginx

vim /opt/nginx/conf/nginx.conf
worker_processes 1;

events { 
worker_connections 1024; 
}

http { 
passenger_root /usr/local/rvm/gems/ree-1.8.7-2012.02/gems/passenger-4.0.14; 
passenger_ruby /usr/local/rvm/wrappers/ree-1.8.7-2012.02/ruby;

client_max_body_size 100m; 
server_names_hash_bucket_size 64;

include mime.types; 
default_type application/octet-stream;

sendfile          on;
keepalive_timeout 65;
server {
listen 80; server_name localhost _ tgym.ru www.tgym.ru;
root /var/www/tgym/public; 
passenger_enabled on; 
}

}