Ветвь dev:

git branch -d dev

Отправка:

git push

Phusion Passenger - модуль для Apache и Nginx

Heroku (production) - см. стр. 52:

gem 'pg'
gem 'rails_12factor'

Bundle:

bundle install --without production

alias:

bwp
heroku login
heroku create # alias: herc
git push heroku master # alias: gphm

Rename:

heroku rename foo

Open:

heroku open # alias: hero

Если проект уже был создан, и надо сделать миграцию базы данных:

heroku run rake db:migrate

Отменить изменения:

git checkout -f

Добавить и отправить:

git remote add orign git@...

git push -u orign --all
  1. Ветвление
  2. Редактирование
  3. Фиксация
  4. Слияние
alias git co = git checkout

Ветвление:

git co -b dev # создание ветки
git branch # список веток

Фиксация:

git status # gs
git commit # gc "Foo"

Слияние:

git checkout master
git merge dev

Модель данных Users + интерфейс = ресурс Users

Scaffold:

rails generate scaffold User name:string email:string

rake db:migrate

Посмотреть список Rake-задач:

rake -T db # по БД
rake -T # все

CRUD:

REST - передача репрезентативного состояния (архитектурный стиль разработки распределённых сетевых систем). Рой Фолдинг, 2000

  • C - POST - CREATE
  • R - GET - READ
  • U - PATCH - UPDATE
  • D - DELETE - DESTROY

Маршруты RESTful - CRUD - операции БД и 4 метода HTTP-запроса + link_to (для ссылки)

  • index - /users - GET - users_path
  • show - /users/1 - GET - user
  • new - /users/new - GET - new_user_path
  • edit - /users/1/edit - GET - edit_user_path(user)
  • create - /users - POST
  • update - /users/1 - PATCH
  • destroy - /users/1 - DELETE - user, method: :delete

Решить, какие контроллеры и методы необходимы: структур. приложение использ. ресурсы которые могут CRUD

controller:

def index
  @users = User.all
end

view:

<% @users.each do |user| %>
  <%= user.name %>
  <%= user.email %>

  <%= link_to 'Show', user %>
  <%= link_to 'Edit', edit_user_path(user) %>
  <%= link_to 'Destroy', user, method: :delete %>
<% end %>

<%= link_to 'New User', new_user_path %>
  • users list - users_path
  • show - user
  • new user - new_user_path
  • edit - edit_user_path(user)
  • destroy - user, method: :delete

routes.rb

Маршрутное правило (направляет запросы к URL в методы контроллера по REST):

resources :users

Валидатор длины /models/…

validates :content, length: {maximum: 140}

user_id

В models:

has_many :posts
belong_to :user

Heroku run:

heroku run rake db:migrate

Rails REST: стандартный набор URL и методов действий контроллеров для взаимодействия с моделями данных.

Валидация наличия содержимого (в model):

validates :content, presence: true

Gem-ы для test в Gemfile:

'minitest-reporters'
'mini_backtrace'
'guard-minitest'
'guard'
heroku logs # hl

Если много статических страниц, то лучше использовать гем high_voltage

Default start page (routes.rb):

root 'application#hello'

Генерировать контроллеры в верблюжьей нотации:

rails generate controller StaticPages home help

# alias rgc

Откат создания контроллера:

rails destroy controller StaticPages home

Откат создания модели:

rails destroy model User
rake db:migrate

Откатить на 1 шаг миграции:

rake db:rollback

Откат к началу:

rake db:migrate VERSION=0

В некоторых средах перед rake надо писать:

bundle exec

Маршруты к методам в routes.rb:

get 'static_pages/home'

Тестирование контроллеров:

test "should get home" do
  get static_pages_home_url
  assert_response: success
end
bundle

Исслед. сообщ. об ошибке:

rake test

КРАСНЫЙ / ЗЕЛЁНЫЙ / РЕФАКТОРИНГ

Проверка заголовка (тест):

assert_select "title", "Foo"

.erb:

<%= provide(:title, "Home") %>
<%= yield(:title) %>

Автозапуск тестов:

bundle exec guard init # alias begi
bundle exec guard # alias beg
# Enter

Когда тормозит:

ps aux | grep spring # узнаем pid
kill -9 [pid] # или
spring stop # или
pkill -9f spring

Смотри мой репо на гитхаб - https://github.com/krdprog/hartl-ror-custom-guardfile

Код Ruby пишем в хелперах

/app/helpers/application-helper.rb

Можно создавать свои вспомогательные функции (методы)

a.class
a.class.superclass.superclass
# наследование классов
class Word
  def palindrome?(string)
    string == string.reverse
  end
end

w = Word.new
w.palindrome?("Foo") #=> false
class Word < String
  def palindrome?
    self == self.reverse
  end
end

s = Word.new("level")
s.palindrome? #=> true
s.size #=> 5

Изменение встроенных классов:

class String
  def palindrome?
    self == self.reverse
  end
end

"level".palindrome? #=> true
"".empty? # Ruby-метод
" ".blank? # Rails-метод
class User
  # создадим методы доступа к атрибутам
  attr_accessor :name :email

  # автоматически вызывается при User.new, аргумент attributes со значением по умолчанию - пустой хеш (nil)
  def initialize(attributes = {})
    @name = attributes[:name]
    @email = attributes[:email]
  end

  # переменные экземпляра (в Rails автоматически доступны во views)
  def formatted_email
    "#{@name} - #{@email}"
  end
end
  • getter - метод чтения
  • setter - метод записи
require './example_user'

example = User.new
example.name = "Foo"
example.email = "foo@bar.com"

example.formatted_email

# или так:
user = User.new(name: "Foo", email: "Bar")

Инициализация объектов передачей хешей в аргументах широко используется в Rails.

Оформление макета:

<%= link_to "Logo", "#", id: "logo" %>

текст ссылки - именованный маршрут - хеш с дополнительными параметрами (в случае выше: CSS id)

Картинка-ссылка:

<%= link_to image_tag("logo.png", alt: "logo"), 'http://krdprog.ru/' %>

Картинки складываем в /app/asserts/images/, но в коде загруженной страницы путь будет виден без images части.

Установим бустрап:

gem 'bootstrap-sass'
bundle install

и, добавить в файл /app/asserts/stylesheets/custom.css.scss:

@import "bootstrap-sprockets";
@import "bootstrap";

Все стили будем прописывать тут: /app/asserts/stylesheets/custom.css.scss

Все таблицы стилей из каталога /app/asserts/stylesheets/ добавятся в файл application.css

Частичные шаблоны

Из основного шаблона можно вынести часть кода в частичные шаблоны и вызвать их в основном.

<%= render 'layouts/header' %>

При этом будет найден и обработан файл /app/views/layouts/_header.html.erb

_foo.html.erb - универсальное соглашени по именованию частичных шаблонов.

Многие для частичных шаблонов используют каталог shared, Хартл предлагает каталог shared использовать для хранения служебных шаблонов использующихся в нескольких страницах, а в layouts - части макета (используемые на каждой странице).

Sass и конвейер ресурсов (asset pipeline)

Конвейер ресурсов значительно упрощает создание и управление статическими ресурсами (CSS, JS, изображения).

3 основных аспекта:

  • каталоги ресурсов
  • файлы манифестов
  • препроцессоры

3 канонических каталога:

  • /app/asserts - ресурсы данного приложения
  • /lib/asserts - ресурсы для библиотек написанных вашей командой разработчиков
  • /vendor/asserts - ресурсы сторонних поставщиков

Файлы манифестов (декларации)

Чтобы сообщить Rails через гем Sprockets как объединить и сформировать в 1 файл CSS и JS файлы.

/app/asserts/stylesheets/application.css

*= require_tree . - включит все каталоги и подкаталоги в /app/asserts/stylesheets
*= require_self - указывает, где будет включаться код самого файла application.css

Смотри подробнее по ссылке: https://guides.rubyonrails.org/asset_pipeline.html и http://rusrails.ru/asset-pipeline

Препроцессоры

сборка ресурсов - подготовка для добавления в макет (прогон через несколько препроцессоров) - комбинирование с помощью файлов манифестов.

  • .scss - Sass
  • .coffee - CofeeScript
  • .erb - Embed Ruby

TODO: Изучить CoffeeScript.

Цепочки препроцессоров для обработки файлов: foo.js.erb.coffee - обработка справа-налево

Эффективность на этапе эксплуатации

Автоматическая автоматизация ресурсов.

  • application.css
  • application.js

Объединение и минимизация.

Sass

Язык определения таблиц стилей.

  • вложения
  • переменные
  • примеси

.scss

custom.css.scss

Вложения

CSS:

.center {
  text-align: center;
}

.center h1 {
  margin-bottom: 10px;
}

Sass:

.center {
  text-align: center;

  h1 {
    margin-bottom: 10px;
  }
}

Вложение правила со ссылкой на родительский элемент:

#logo {
  margin-left: 10px;
  color: #fff;

  &:hover {
    text-decoration: none;
  }
}

Sass заменяет &:hover на #logo:hover

Переменные в Sass

$light-gray: #777;

color: $light-gray;

В Less, переменные обозначаются знаком @, в Sass - $

Ссылки в макете:

Home     | /        | root_path
About    | /about   | about_path
Help     | /help    | help_path
Contact  | /contact | contact_path
Signup   | /signup  | signup_path
Login    | /login   | login_path
<%= link_to "About", about_path %>

С помощью файла /config/routes.rb Rails определяет соответствия между именами маршрутов и адресами URL.

root_path -> '/'
root_url -> 'https://foo.com/'

Общее соглашение использовать _path, кроме случаев переадресации (стандарт HTTP требует полный адрес URL) - _url

Чтобы определить именованные маршруты, надо поменять правила в /config/routes.rb:

get 'static_pages/help'
# поменять на:
get 'help' => 'static_pages#help'

Второй вариант передаёт запрос GET к адресу URL /help в метод help контроллера StaticPages и создаётся именованные маршруты help_path и help_url

Тесты для проверки ссылок в макете:

Проверим ссылки в макете с помощью интеграционных тестов.

Создадим тест site_layout

rails g integration_test site_layout

Или используя алиас (создал для себя rgit):

rgit site_layout

Будет создан файл /test/integration/site_layout_test.rb

Добавим в него тест проверки наших ссылок:

require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
  end

end

Дополнительно потребовался gem, добавить в Gemfile и сделать bundle install:

gem 'rails-controller-testing'

Запустим интеграционный тест:

bundle exec rake test:integration

И, все тесты:

bundle exec rake test

Примеры assert_select:

assert_select "div"                         | <div>faz</div>
assert_select "div", "foo"                  | <div>foo</div>
assert_select "div.nav"                     | <div class="nav">foo</div>
assert_select "div#profile"                 | <div id="profile">foo</div>
assert_select "div[name=ku]"                | <div name="ku">foo</div>
assert_select "a[href=?]", '/', count: 1    | <a href="/">foo</a>
assert_select "a[href=?]", '/', text: "bar" | <a href="/">bar</a>

Подготовим всё для авторизации:

Создадим контроллер Users и метод действия new:

rails g controller Users new

Будет создан контроллер, заглушка представления new и тест.

И, создадим маршрут в /config/routes.rb

get 'signup' => 'users#new'

Ссылка на страницу регистрации:

<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>