Rails руководство на русском

Это руководство раскрывает установку и запуск Ruby on Rails.

После его прочтения, вы узнаете:

  • Как установить Rails, создать новое приложение на Rails и присоединить ваше приложение к базе данных.
  • Общую структуру приложения на Rails.
  • Основные принципы MVC (Model, View, Controller — «Модель-представление-контроллер») и дизайна, основанного на RESTful.
  • Как быстро генерировать изначальный код приложения на Rails.

Это руководство рассчитано на новичков, которые хотят создать приложение на Rails с нуля. Оно не предполагает, что вы раньше работали с Rails.

Rails – фреймворк для веб-разработки, написанный на языке программирования Ruby. Если у вас нет опыта в Ruby, возможно вам будет тяжело сразу приступить к изучению Rails. Есть несколько хороших англоязычных ресурсов, посвященных изучению Ruby, например:

  • Официальный сайт языка программирования Ruby
  • Список бесплатных книг по программированию

Обращайте внимание, что некоторые источники, хотя все еще великолепные, но все же покрывают старые версии Ruby, и могут не включать некоторые элементы синтаксиса, которые вы увидите в повседневной разработке на Rails.

Rails — фреймворк для веб-разработки, написанный на языке программирования Ruby. Он разработан, чтобы сделать программирование веб-приложений проще, так как использует ряд допущений о том, что нужно каждому разработчику для создания нового проекта. Он позволяет вам писать меньше кода в процессе программирования, в сравнении с другими языками и фреймворками. Профессиональные разработчики на Rails также отмечают, что с ним разработка веб-приложений более забавна =)

Rails — своевольный программный продукт. Он делает предположение, что имеется «лучший» способ что-то сделать, и он так разработан, что стимулирует этот способ — а в некоторых случаях даже препятствует альтернативам. Если изучите «The Rails Way», то, возможно, откроете в себе значительное увеличение производительности. Если будете упорствовать и переносить старые привычки с других языков в разработку на Rails, и попытаетесь использовать шаблоны, изученные где-то еще, ваш опыт разработки будет менее счастливым.

Философия Rails включает два важных ведущих принципа:

  • Don’t Repeat Yourself: DRY — это принцип разработки ПО, который гласит, что «Каждый кусочек информации должен иметь единственное, неизбыточное, авторитетное представление в системе». Не пишите одну и ту же информацию снова и снова, код будет легче поддерживать, и он будет более расширяемым и менее ошибочным.
  • Convention Over Configuration: у Rails есть мнения о наилучших способах делать множество вещей в веб-приложении, и по умолчанию выставлены эти соглашения, вместо того, чтобы заставлять вас по мелочам править многочисленные конфигурационные файлы.

Лучший способ использования этого руководства — проходить его шаг за шагом. Все шаги существенны для запуска служащего примером приложения, кроме них больше не требуется какого-либо дополнительного кода или шагов.

Следуя этому руководству, вы создадите проект Rails с названием blog, очень простой веб-блог. Прежде чем начнем создавать приложение, нужно убедиться, что сам Rails установлен.

Нижеследующие примеры используют $ для обозначения строки ввода терминала в UNIX-подобных операционных системах, хотя он может быть настроен по-другому. Если используется Windows, строка будет выглядеть наподобие C:\source_code>

Перед установкой Rails необходимо проверить, чтобы в вашей системе были установлены необходимые предварительные зависимости. К ним относятся:

  • Ruby
  • SQLite3

Откройте приложения для командной строки. На macOS откройте Terminal.app; на Windows выберите «Run» в меню Start и напишите cmd.exe. Любые команды, начинающиеся со знака доллара $ должны быть запущены в командной строке. Убедитесь, что у вас установлена текущая версия Ruby:

$ ruby --version
ruby 2.7.0

Rails требует, чтобы был установлен Ruby версии 2.7.0 или новее. Предпочтительно использовать последнюю версию Ruby. Если номер версии меньше этой (такие как 2.3.7 или 1.8.7), нужно будет установить новую копию Ruby.

Чтобы установить Ruby на Windows, сначала нужно установить Ruby Installer.

Дополнительные методы установки для большинства операционных систем можно увидеть на ruby-lang.org.

Вам также понадобится установка базы данных SQLite3.

Многие популярные UNIX-подобные ОС поставляются с приемлемой версией SQLite3. Прочие пользователи могут обратиться к инструкциям по установке на сайте SQLite3.

Проверьте, что он правильно установлен и содержится в вашем PATH загрузки:

Программа должна сообщить свою версию.

Для установки Rails используйте команду gem install, представленную RubyGems:

Чтобы проверить, что все установлено верно, нужно выполнить следующее в новом терминале:

Если выводится что-то вроде «Rails 7.0.0», можно продолжать.

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

Для использования этого генератора, откройте терминал, войдите в папку, в которой у вас есть права на создание файлов и запустите:

Это создаст приложение на Rails с именем Blog в директории blog и установит гемы, зависимости от которых упомянуты в Gemfile при использовании bundle install.

Можно посмотреть все возможные опции командной строки, которые принимает генератор приложения на Rails, запустив rails new --help.

После того, как вы создали приложение blog, перейдите в его папку:

В директории blog будет несколько автоматически сгенерированных файлов и папок, задающих структуру приложения на Rails. Большая часть работы в этом самоучителе будет происходить в папке app, но сейчас пробежимся по функциям каждой папки, которые создает Rails в новом приложении по умолчанию:

Файл/Папка Назначение
app/ Содержит контроллеры, модели, вью, хелперы, рассыльщики, каналы, задания и ассеты вашего приложения. Мы рассмотрим эту папку подробнее далее.
bin/ Содержит скрипты rails, которые стартуют ваше приложение, также директория может содержать другие скрипты которые вы используете для настройки, обновления, деплоя или запуска.
config/ Содержит конфигурации маршрутов, базы данных вашего приложения, и т.д. Более подробно это раскрыто в Конфигурирование приложений на Rails
config.ru Конфигурация Rack для серверов, основанных на Rack, используемых для запуска приложения. Подробнее о Rack смотрите на сайте Rack.
db/ Содержит текущую схему вашей базы данных, а также миграции базы данных.
Gemfile
Gemfile.lock
Эти файлы позволяют указать, какие зависимости от гемов нужны для вашего приложения на Rails. Эти файлы используются гемом Bundler. Подробнее о Bundler смотрите на сайте Bundler.
lib/ Внешние модули для вашего приложения.
log/ Файлы логов приложения.
public/ Содержит статичные файлы и скомпилированные ассеты. Когда ваше приложение запущено, эта директория будет представлена как есть.
Rakefile Этот файл находит и загружает задачи, которые могут быть запущены в командной строке. Определенная задача доступна во всех компонентах Rails. Вместо изменения Rakefile, можно добавить свои собственные задачи, добавив файлы в директорию lib/tasks приложения.
README.md Это вводный мануал для вашего приложения. Его следует отредактировать, чтобы рассказать остальным, что ваше приложение делает, как его настроить, и т.п.
storage/ Файлы Active Storage для сервиса Disk. Это раскрывается в руководстве Обзор Active Storage.
test/ Юнит-тесты, фикстуры и прочий аппарат тестирования. Это раскрывается в руководстве Тестирование приложений на Rails
tmp/ Временные файлы (такие как файлы кэша и pid)
vendor/ Место для кода сторонних разработчиков. В типичном приложении на Rails включает внешние гемы.
.gitattributes Этот файл определяет метаданные для определенных путей в репозитории git. Эти метаданные могут быть использованы git и другими инструментами для улучшения их поведения. Подробности смотрите в документации gitattributes.
.gitignore Этот файл сообщает git, какие файлы (явно или по шаблону) ему следует игнорировать. Подробнее об игнорировании файлов смотрите GitHub — Ignoring files.
.ruby-version Этот файл содержит дефолтную версию Ruby.

Для начала, давайте выведем на экран какой-либо текст. Для этого нужен запущенный сервер вашего приложения на Rails.

Фактически у вас уже есть функциональное приложение на Rails. Чтобы убедиться, нужно запустить веб-сервер на вашей машине. Это можно осуществить, запустив следующую команду из директории blog:

Если вы используете Windows, вы должны передавать скрипты из папки bin непосредственно в интерпретатор Ruby, то есть ruby bin\rails server.

Сжатие ассетов JavaScript требует среды выполнения JavaScript в вашей системе, и его отсутствие приведет к ошибке execjs во время сжатия ассетов. Обычно macOS и Windows поставляются с установленной средой выполнения JavaScript. therubyrhino — рекомендованная среда выполнения для пользователей JRuby, она добавляется в Gemfile, если приложение генерируется под JRuby. Можно узнать все о поддерживаемых средах выполнения в ExecJS

Это запустит Puma, веб-сервер, распространяющийся с Rails по умолчанию. Чтобы увидеть приложение в действии, откройте окно браузера и пройдите по адресу http://localhost:3000. Вы должны увидеть дефолтную информационную страницу Rails:

скриншот стартовой страницы Rails

Когда захотите остановить веб-сервер, нажмите Ctrl+C в терминале, где он запущен. В среде development, Rails в основном не требует остановки сервера; все изменения, которые Вы делаете в файлах, автоматически подхватываются сервером.

Стартовая страница Rails это smoke test для нового приложения на Rails: она показывает, что ваши программы настроены достаточно правильно для отображения страницы.

Чтобы Rails сказал «Привет», нужно создать, как минимум, маршрут, контроллер с экшном и вью (представление). Маршрут связывает запрос с экшном контроллера. Экшн контроллера выполняет необходимую работу для обработки запроса и подготавливает необходимые данные для вью. Вью отображает данные в желаемом формате.

В терминах реализации: Маршруты это правила, написанные на Ruby DSL (предметно-ориентированном языке). Контроллеры — это классы Ruby, и их публичные методы — это экшны. И вью — это шаблоны, обычно написанные на смеси HTML и Ruby.

Давайте начнем с добавления маршрута к нашему файлу маршрутов, config/routes.rb, в самом верху блока Rails.application.routes.draw:

Rails.application.routes.draw do
  get "/articles", to: "articles#index"

  # О подробностях DSL, доступного в этом файле, написано в http://rusrails.ru/routing
end

Вышеприведенный маршрут объявляет, что запросы GET /articles связываются с экшном index в ArticlesController.

Для создания ArticlesController и его экшна index, мы запустим генератор контроллера (с опцией --skip-routes, так как у нас уже есть подходящий маршрут):

$ bin/rails generate controller Articles index --skip-routes

Rails создаст несколько файлов.

create  app/controllers/articles_controller.rb
invoke  erb
create    app/views/articles
create    app/views/articles/index.html.erb
invoke  test_unit
create    test/controllers/articles_controller_test.rb
invoke  helper
create    app/helpers/articles_helper.rb
invoke    test_unit

Наиболее важным из них является файл контроллера, app/controllers/articles_controller.rb. Давайте посмотрим на него:

class ArticlesController < ApplicationController
  def index
  end
end

Экшн index пустой. Когда экшн не рендерит явно вью (или иным способом создает отклик HTTP), Rails автоматически отрендерит вью, соответствующую имени контроллера и экшну. Convention Over Configuration! Вью располагаются в директории app/views. Таким образом, экшн index по умолчанию отрендерит app/views/articles/index.html.erb.

Давайте откроем файл app/views/articles/index.html.erb и заменим его содержимое на:

Если до этого вы остановили веб сервер для запуска генератора контроллера, перезапустите его с помощью bin/rails server. Теперь посетите http://localhost:3000/articles, чтобы увидеть наш текст отображенным!

В настоящий момент http://localhost:3000 все еще отображает страницу с логотипом Ruby on Rails. Давайте также отобразим наш текст «Hello, Rails!» на http://localhost:3000. Для этого мы добавим маршрут, соответствующий корневому пути нашего приложения к соответствующему контроллеру и экшну.

Откройте config/routes.rb и добавьте следующий маршрут root вверху блока Rails.application.routes.draw:

Rails.application.routes.draw do
  root "articles#index"

  get "/articles", to: "articles#index"
end

Теперь можно видеть наш текст «Hello, Rails!» при посещении http://localhost:3000, что подтверждает то, что маршрут root также связан с экшном index в ArticlesController.

Чтобы узнать больше о роутинге, обратитесь к руководству Роутинг в Rails.

Приложения Rails не используют require для загрузки кода приложения.

Вы, возможно, заметили, что ArticlesController наследуется от ApplicationController, но app/controllers/articles_controller.rb не содержит чего-то наподобие

require "application_controller" # НЕ ДЕЛАЙТЕ ТАК.

Классы и модули приложения доступны отовсюду, вам не нужно и не следует загружать что-то из app с помощью require. Эта особенность называется автоматическая загрузка, и о ней можно узнать подробнее в Автозагрузка и перезагрузка констант.

Вызовы require нужны только в двух случаях:

  • Чтобы загружать файлы из директории lib.
  • Чтобы загружать зависимости гемов, у которых require: false в Gemfile.

Только что мы обсудили маршруты, контроллеры, экшны и вью. Это все типичные части веб приложения, соответствующего паттерну MVC (Model-View-Controller). MVC это шаблон проектирования, разделяющий ответственности приложения для его упрощения. Rails по соглашению следует этому шаблону проектирования.

Поскольку у нас уже есть контроллер и вью, давайте сгенерируем следующую часть: модель.

Модель это класс Ruby, используемый для представления данных. Кроме этого, модели могут взаимодействовать с базой данных приложения с помощью особенности Rails, называемой Active Record.

Для определения модели используем генератор модели:

$ bin/rails generate model Article title:string body:text

Имена моделей в единственном числе, так как инициализированная модель представляет единственную запись данных. Чтобы запомнить это соглашение, думайте о том, как вы хотели вызвать конструктор модели: мы хотим писать Article.new(...), а не Articles.new(...).

Это создаст несколько файлов:

invoke  active_record
create    db/migrate/<timestamp>_create_articles.rb
create    app/models/article.rb
invoke    test_unit
create      test/models/article_test.rb
create      test/fixtures/articles.yml

Два файла, на которых мы сфокусируемся, это файл миграции (db/migrate/<timestamp>_create_articles.rb) и файл модели (app/models/article.rb).

Миграции используются для изменения структуры базы данных приложения. В приложениях Rails миграции написаны на Ruby, поэтому они могут быть не зависящими от базы данных.

Давайте посмотрим на содержимое нового файла миграции:

class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :body

      t.timestamps
    end
  end
end

Вызов create_table указывает, как должна быть сконструирована таблица articles. По умолчанию метод create_table добавляет столбец id в качестве автоматически увеличивающегося первичного ключа. Таким образом, у первой записи в таблице будет id 1, у следующей записи id 2, и так далее.

В блоке для create_table определены два столбца: title и body. Они были добавлены генератором, так как мы включили их в команду генерации (bin/rails generate model Article title:string body:text).

В последней строчке блока вызывается t.timestamps. Этот метод определяет два дополнительных столбца с именами created_at и updated_at. Как мы увидим, Rails позаботится о них, устанавливая значения при создании или обновлении объекта модели.

Давайте запустим нашу миграцию с помощью следующей команды:

Эта команда выведет, что таблица была создана:

==  CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0018s
==  CreateArticles: migrated (0.0018s) ==========================

Теперь мы можем взаимодействовать с этой таблицей с помощью нашей модели.

Чтобы поиграть немного с нашей моделью, мы собираемся воспользоваться особенностью Rails, называемой консоль. Консоль это интерактивная среда программирования, похожая на irb, но автоматически загружающая Rails и код нашего приложения.

Давайте запустим консоль с помощью команды:

Вы должны увидеть интерфейс irb наподобие:

Loading development environment (Rails 7.0.0)
irb(main):001:0>

В этом интерфейсе можно инициализировать новый объект Article:

irb> article = Article.new(title: "Hello Rails", body: "I am on Rails!")

Важно отметить, что мы только инициализировали этот объект. Этот объект вообще не сохранен в базе данных. В настоящий момент он доступен только в консоли. Чтобы сохранить его в базу данных, нужно вызвать save:

irb> article.save
(0.1ms)  begin transaction
Article Create (0.4ms)  INSERT INTO "articles" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "Hello Rails"], ["body", "I am on Rails!"], ["created_at", "2020-01-18 23:47:30.734416"], ["updated_at", "2020-01-18 23:47:30.734416"]]
(0.9ms)  commit transaction
=> true

Вышеуказанный вывод показывает запрос базы данных INSERT INTO "articles" .... Это показывает, что статья была вставлена в нашу таблицу. И если мы снова взглянем на объект article, то увидим, что произошло нечто интересное:

irb> article
=> #<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">

Теперь у объекта установлены атрибуты id, created_at и updated_at. Rails сделал это, когда мы сохранили объект.

Когда мы хотим извлечь эту статью из базы данных, можно вызвать find на модели и передать id в качестве аргумента:

irb> Article.find(1)
=> #<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">

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

irb> Article.all
=> #<ActiveRecord::Relation [#<Article id: 1, title: "Hello Rails", body: "I am on Rails!", created_at: "2020-01-18 23:47:30", updated_at: "2020-01-18 23:47:30">]>

Этот метод возвращает объект ActiveRecord::Relation, о котором можно думать, как о массиве с особыми способностями.

Модели это последний кусочек пазла MVC. Далее мы соединим все кусочки вместе.

Давайте вернемся к нашему контроллеру в app/controllers/articles_controller.rb и изменим экшн index, чтобы он извлекал все статьи из базы данных:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end
end

К переменным экземпляра контроллера можно получить доступ из вью. Это означает, что мы можем ссылаться на @articles в app/views/articles/index.html.erb. Давайте откроем этот файл и заменим его содержимое на:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= article.title %>
    </li>
  <% end %>
</ul>

Вышеприведенный код это смесь HTML и ERB. ERB это система шаблонирования, которая вычисляет код Ruby, вложенный в документ. Тут мы видим два типа тегов ERB: <% %> и <%= %>. Тег <% %> означает «вычислить заключенный код Ruby». Тег <%= %> означает «вычислить заключенный код Ruby и вывести значение, которое он возвратит». Все, что можно написать в обычной программе на Ruby, можно вложить в эти теги ERB, хотя обычно лучше сохранять содержимое тегов ERB кратким, для читаемости.

Так как мы не хотим вывести значение, возвращаемое @articles.each, мы заключили этот код в <% %>. Но, поскольку мы хотим вывести значение, возвращаемое article.title (для каждой статьи), мы заключили этот код в <%= %>.

Окончательный результат можно увидеть, посетив http://localhost:3000. (Помните, что bin/rails server должен быть запущен!) Вот что произойдет при этом:

  • Браузер сделает запрос: GET http://localhost:3000.
  • Наше приложение Rails получит этот запрос.
  • Роутер Rails свяжет корневой маршрут с экшном index в ArticlesController.
  • Экшн index использует модель Article для извлечения всех статей из базы данных.
  • Rails автоматически отрендерит вью app/views/articles/index.html.erb.
  • Вычисляется код ERB во вью для вывода HTML.
  • Сервер отправит отклик, содержащий HTML, обратно браузеру.

Мы соединили все кусочки MVC вместе, и теперь у нас есть наш первый экшн контроллера! Далее мы двинемся ко второму экшну.

Почти все веб приложения используют операции CRUD (Create, Read, Update, and Delete). Можно обнаружить, что большая часть работы вашего приложения это CRUD. Rails знает об этом и предоставляет много особенностей для упрощения кода, осуществляющего CRUD.

Давайте исследуем эти возможности, добавив больше функционала в наше приложение.

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

Начнем с добавления нового маршрута, направляющего на новый экшн контроллера (который затем тоже добавим). Откройте config/routes.rb и вставьте последний маршрут, показанный тут:

Rails.application.routes.draw do
  root "articles#index"

  get "/articles", to: "articles#index"
  get "/articles/:id", to: "articles#show"
end

Новый маршрут является еще одним маршрутом get, но есть кое-что дополнительное в его пути: :id. Это означает параметр маршрута. Параметр маршрута захватывает сегмент пути запроса, и кладет это значение в хэш params, доступный в экшне контроллера. Например, при обработке запроса GET http://localhost:3000/articles/1, 1 будет захвачено как значение для :id, и будет доступно как params[:id] в экшне show в ArticlesController.

Теперь давайте добавим этот экшн show, ниже экшна index в app/controllers/articles_controller.rb:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end
end

Экшн show вызывает Article.find (упомянутый ранее) с ID, захваченным параметром маршрута. Возвращаемая статья хранится в переменной экземпляра @article, поэтому она доступна во вью. По умолчанию экшн show отрендерит app/views/articles/show.html.erb.

Давайте создадим app/views/articles/show.html.erb со следующим содержимым:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

Теперь можно увидеть статью при посещении http://localhost:3000/articles/1!

В завершении, давайте добавим удобный способ перейти на страницу статьи. Мы свяжем заголовок каждой статьи в app/views/articles/index.html.erb с ее страницей:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <a href="/articles/<%= article.id %>">
        <%= article.title %>
      </a>
    </li>
  <% end %>
</ul>

К этому моменту мы раскрыли «R» (Read) из CRUD. Со временем мы раскроем «C» (Create), «U» (Update) и «D» (Delete). Как вы, возможно, догадались, мы сделаем это, добавив новые маршруты, экшны контроллера и вью. Всякий раз, когда у нас есть такая комбинация маршрутов, экшнов контроллера и вью, работающих вместе для выполнения операций CRUD на сущности, мы называем эту сущность ресурсом. Например, в нашем приложении, мы бы назвали статью ресурсом.

Rails предоставляет маршрутный метод resources, который связывает все общепринятые маршруты для коллекции ресурсов, таких как статьи. Поэтому, до того, как мы перейдем к разделам «C», «U» и «D», давайте заменим два маршрута get в config/routes.rb на resources:

Rails.application.routes.draw do
  root "articles#index"

  resources :articles
end

Можно посмотреть, какие маршруты связаны, запустив команду bin/rails routes:

$ bin/rails routes
      Prefix Verb   URI Pattern                  Controller#Action
        root GET    /                            articles#index
    articles GET    /articles(.:format)          articles#index
 new_article GET    /articles/new(.:format)      articles#new
     article GET    /articles/:id(.:format)      articles#show
             POST   /articles(.:format)          articles#create
edit_article GET    /articles/:id/edit(.:format) articles#edit
             PATCH  /articles/:id(.:format)      articles#update
             DELETE /articles/:id(.:format)      articles#destroy

Метод resources также настраивает вспомогательные методы URL и путей, которые можно использовать для предотвращения зависимостей нашего кода от настроек определенного маршрута. Значения выше в столбце «Prefix» плюс суффикс _url или _path формируют имена этих хелперов. Например, хелпер article_path возвращает "/articles/#{article.id}" для заданной статьи. Его можно использовать для приведения в порядок наших ссылок в app/views/articles/index.html.erb:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <a href="<%= article_path(article) %>">
        <%= article.title %>
      </a>
    </li>
  <% end %>
</ul>

Однако, мы сделаем еще один шаг вперед и используем хелпер link_to. Хелпер link_to создает ссылку с первым аргументом в качестве текста ссылки и вторым аргументом в качестве адреса ссылки. Если мы передадим объект модели как второй аргумент, link_to вызовет подходящий хелпер пути для преобразования объекта в путь. Например, если мы передадим статью, link_to вызовет article_path. Таким образом, app/views/articles/index.html.erb станет:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %>
    </li>
  <% end %>
</ul>

Отлично!

Теперь мы подходим к «C» (Create) из CRUD. Обычно, в веб приложениях, создание нового ресурса это многошаговый процесс. Сначала пользователь запрашивает форму для заполнения. Затем пользователь отправляет форму. Если нет ошибок, то ресурс создается, и отображается некоторое подтверждение. Иначе, форма снова отображается с сообщениями об ошибке, и процесс повторяется.

В приложении Rails эти шаги традиционно обрабатываются экшнами контроллера new и create. Давайте добавим типичную реализацию этих экшнов в app/controllers/articles_controller.rb, ниже экшна show:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(title: "...", body: "...")

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end
end

Экшн new инициализирует новую статью, но не сохраняет ее. Эта статья будет использована во вью при построении формы. По умолчанию экшн new будет рендерить app/views/articles/new.html.erb, которую мы создадим далее.

Экшн create инициализирует новую статью со значениями для заголовка и содержимого и пытается сохранить ее. Если статью успешно сохранена, экшн перенаправляет браузер на страницу статьи "http://localhost:3000/articles/#{@article.id}". Иначе экшн отображает форму заново, отрендерив app/views/articles/new.html.erb с кодом статуса 422 Unprocessable Entity. Тут title и body фиктивные значения. После того, как мы создадим форму, мы вернемся и изменим их.

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

Мы будем использовать особенность Rails, называемую form builder, для создания нашей формы. Используя построитель форм, можно, используя минимальное количество кода, вывести полностью настроенную форму, следующую соглашениям Rails.

Давайте создадим app/views/articles/new.html.erb со следующим содержимым:

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

Вспомогательный метод form_with инициализирует построитель форм. В блоке form_with мы вызываем на построителе форм методы, такие как label и text_field для вывода подходящих элементов формы.

Результирующий вывод от вызова form_with будет выглядеть так:

<form action="/articles" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="...">

  <div>
    <label for="article_title">Title</label><br>
    <input type="text" name="article[title]" id="article_title">
  </div>

  <div>
    <label for="article_body">Body</label><br>
    <textarea name="article[body]" id="article_body"></textarea>
  </div>

  <div>
    <input type="submit" name="commit" value="Create Article" data-disable-with="Create Article">
  </div>
</form>

Отправленные данные формы вкладываются в хэш params, вместе с захваченными параметрами маршрута. Таким образом, экшн create имеет доступ к отправленному заголовку как params[:article][:title] и к отправленному содержимому как params[:article][:body]. Эти значения можно передать в Article.new отдельно, но это может быть некрасиво и подвержено ошибкам. И это будет еще хуже, когда мы добавим больше полей.

Вместо этого, мы передадим единственный хэш, содержащий значения. Однако, мы все еще должны указать, какие значения допустимы в этом хэше. В противном случае, злоумышленник потенциально может отправить дополнительные поля формы и перезаписать конфиденциальные данные. Фактически, если мы передадим нефильтрованный хэш params[:article] непосредственно в Article.new, Rails вызовет ForbiddenAttributesError, чтобы предупредить нас о проблеме. Таким образом, мы будем использовать особенность Rails, названную Strong Parameters, для фильтрации params. Представьте это как сильную типизацию для params.

Давайте добавим приватный метод внизу app/controllers/articles_controller.rb, названный article_params, фильтрующий params. И давайте изменим create, чтобы использовать его:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

Как мы видели, создание ресурса это многоступенчатый процесс. Обработка неправильного пользовательского ввода это еще один шаг этого процесса. Rails предоставляет особенность валидации, чтобы помочь нам разобраться с неправильным пользовательским вводом. Валидации это правила, проверяемые до сохранения объекта модели. Если любая из проверок провалится, сохранение будет прервано, и соответствующие сообщения об ошибке будут добавлены в атрибут errors у объекта модели.

Давайте добавим некоторые валидации в нашу модель в app/models/article.rb:

class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

Первая валидация объявляет, что должно присутствовать значение title. Так как title строка, это означает, что значение title должно содержать как минимум один не пробельный символ.

Вторая валидация объявляет, что значение body также должно присутствовать. Кроме этого, она объявляет, что длина значения body должно быть как минимум 10 символов.

Возможно, вам интересно, где определены атрибуты title и body. Active Record автоматически определяет атрибуты модели для каждого столбца таблицы, таким образом, не нужно объявлять эти атрибуты в файле модели.

С имеющимися валидациями, давайте изменим app/views/articles/new.html.erb для отображения любых сообщений об ошибке для title и body:

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
    <% @article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %><br>
    <% @article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

Метод full_messages_for возвращает массив дружелюбных сообщений об ошибке для определенного атрибута. Если для атрибута нет ошибок, этот массив будет пустым.

Чтобы понять, как это все работает, давайте снова взглянем на экшны new и create контроллера:

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

При посещении http://localhost:3000/articles/new, запрос GET /articles/new направляется на экшн new. Экшн new не пытается сохранить @article. Следовательно, валидации не проверяются, и сообщений об ошибке не будет.

При отправке формы, запрос POST /articles направляется на экшн create. Экшн create пытается сохранить @article. Следовательно, валидации проверяются. Если любая из валидаций падает, @article не будет сохранена, и app/views/articles/new.html.erb будет отрендерена с сообщением об ошибке.

Теперь мы можем создать статью, посетив http://localhost:3000/articles/new. Для завершения давайте добавим ссылку на эту страницу внизу app/views/articles/index.html.erb:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %>
    </li>
  <% end %>
</ul>

<%= link_to "New Article", new_article_path %>

Мы покрыли «CR» от CRUD. Теперь перейдем к «U» (Update). Обновление ресурса очень похоже на создание ресурса. Они оба многоступенчатые процессы. Во-первых, пользователь запрашивает форму для редактирования данных. Затем пользователь отправляет форму. Затем, если не было ошибок, ресурс обновляется. В противном случае, форма снова отображается с сообщениями об ошибке, и процесс повторяется.

По соглашениям, эти шаги обрабатываются экшнами edit и update контроллера. Давайте добавим типичную реализацию этих экшнов в app/controllers/articles_controller.rb, ниже экшнаcreate:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])

    if @article.update(article_params)
      redirect_to @article
    else
      render :edit, status: :unprocessable_entity
    end
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

Обратите внимание, как похожи экшны edit и update на экшны new и create.

Экшн edit извлекает статью из базы данных и сохраняет ее в @article, таким образом ее можно использовать при построении формы. По умолчанию экшн edit отрендерит app/views/articles/edit.html.erb.

Экшн update (пере)извлекает статью из базы данных и пытается обновить ее с помощью отправленных данных формы, фильтрованных в article_params. Если ни одна валидация не упадет, и обновление будет успешным, этот экшн перенаправит браузер на страницу статьи. В противном случае, экшн повторно отобразит форму — с сообщениями об ошибке — отрендерив app/views/articles/edit.html.erb.

Форма edit будет выглядеть такой же, как форма new. Даже код будет тем же, благодаря построителю форм Rails и ресурсному роутингу. Построитель форм автоматически настроит форму для осуществления подходящего типа запроса, основываясь на том, был ли объект модели ранее сохранен.

Так как код будет тем же самым, мы собираемся рефакторить его в совместную вью, называемую партиал. Давайте создадим app/views/articles/_form.html.erb со следующим содержимым:

<%= form_with model: article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
    <% article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %><br>
    <% article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

Вышеприведенный код тот же самый, что и форма в app/views/articles/new.html.erb, за исключением того, что все случаи @article заменены на article. Так как партиалы являются совместным кодом, хорошим тоном является не делать их зависимыми от определенных переменных экземпляра, установленных экшном контроллера. Вместо этого, мы передадим статью в партиал как локальную переменную.

Давайте обновим app/views/articles/new.html.erb, чтобы использовать этот партиал с помощью render:

<h1>New Article</h1>

<%= render "form", article: @article %>

Имя файла партиала должно начинаться на подчеркивание, т.е. _form.html.erb. Но при рендеринге ссылаемся на него без подчеркивания, т.е. render "form".

И теперь давайте создадим очень похожий app/views/articles/edit.html.erb:

<h1>Edit Article</h1>

<%= render "form", article: @article %>

Теперь мы можем обновлять статью, посетив страницу ее редактирования, т.е. http://localhost:3000/articles/1/edit. Для завершения, давайте добавим ссылку на страницу редактирования внизу app/views/articles/show.html.erb:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
</ul>

Наконец, мы добрались до «D» (Delete) из CRUD. Удаление ресурса это более простой процесс, чем создание или обновление. Он требует только маршрут и экшн контроллера. И наш ресурсный роутинг (resources :articles) уже предоставляет этот маршрут, связывающий запросы DELETE /articles/:id с экшном destroy в ArticlesController.

Итак, давайте добавим типичный экшн destroy в app/controllers/articles_controller.rb ниже экшна update:

class ArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])

    if @article.update(article_params)
      redirect_to @article
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @article = Article.find(params[:id])
    @article.destroy

    redirect_to root_path, status: :see_other
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
end

Экшн destroy извлекает статью из базы данных, и вызывает destroy на ней. Затем он перенаправляет браузер на корневой путь со статусом кода 303 See Other.

Мы выбрали перенаправление на корневой путь, так как это наша основная точка доступа к статьям. В других обстоятельствах можно было бы выбрать перенаправление на articles_path.

Теперь давайте добавим ссылку внизу app/views/articles/show.html.erb, чтобы мы могли удалить статью с ее страницы:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

В вышеприведенном коде мы используем опцию data для установки HTML-атрибутов data-turbo-method и data-turbo-confirm ссылки «Destroy». Оба этих атрибута подключаются к Turbo, который по умолчанию включен в новые приложения Rails. data-turbo-method="delete" заставит ссылку сделать запрос DELETE вместо запроса GET. data-turbo-confirm="Are you sure?" приведет к появлению диалогового окна подтверждения при нажатии на ссылку. Если пользователь отменит диалог, запрос будет прерван.

Вот и все! Теперь можно просматривать, создавать, обновлять и удалять статьи!

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

Мы намереваемся использовать тот же генератор, что мы использовали ранее при создании модели Article. В этот раз мы создадим модель Comment, содержащую ссылку на статью. Запустите следующую команду в терминале:

$ bin/rails generate model Comment commenter:string body:text article:references

Эта команда генерирует четыре файла:

Файл Назначение
db/migrate/20140120201010_create_comments.rb Миграция для создания таблицы comments в вашей базе данных (ваше имя файла будет включать другую временную метку)
app/models/comment.rb Модель Comment
test/models/comment_test.rb Каркас для тестирования модели комментария
test/fixtures/comments.yml Образцы комментариев для использования в тестировании

Сначала взглянем на app/models/comment.rb:

class Comment < ApplicationRecord
  belongs_to :article
end

Это очень похоже на модель Article, которую мы видели ранее. Разница в строчке belongs_to :article, которая устанавливает связь Active Record. Вы ознакомитесь со связями в следующем разделе руководства.

Ключевое слово (:references), использованное в команде консоли, это специальный тип данных для моделей. Он создает новый столбец в вашей базе данных с именем представленной модели с добавленным _id, который может содержать числовые значения. Чтобы лучше понять, проанализируйте файл db/schema.rb после выполнения миграции.

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

class CreateComments < ActiveRecord::Migration[7.0]
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
      t.references :article, null: false, foreign_key: true

      t.timestamps
    end

  end
end

Строчка t.references создает числовой столбец с именем article_id, индекс для него, и ограничение внешнего ключа, указывающего на столбец id таблицы articles. Далее запускаем миграцию:

Rails достаточно сообразителен, чтобы выполнять только те миграции, которые еще не были запущены для текущей базы данных, в нашем случае Вы увидите:

==  CreateComments: migrating =================================================
-- create_table(:comments)
   -> 0.0115s
==  CreateComments: migrated (0.0119s) ========================================

Связи Active Record позволяют Вам легко объявлять отношения между двумя моделями. В случае с комментариями и статьями, вы можете описать отношения следующим образом:

  • Каждый комментарий принадлежит одной статье.
  • Одна статья может иметь много комментариев.

Фактически, это очень близко к синтаксису, который использует Rails для объявления этой связи. Вы уже видели строчку кода в модели Comment (app/models/comment.rb), которая делает каждый комментарий принадлежащим статье:

class Comment < ApplicationRecord
  belongs_to :article
end

Вам нужно отредактировать app/models/article.rb, добавив другую сторону связи:

class Article < ApplicationRecord
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

Эти два объявления автоматически делают доступным большое количество возможностей. Например, если у вас есть переменная экземпляра @article, содержащая статью, вы можете получить все комментарии, принадлежащие этой статье, в массиве, вызвав @article.comments.

Как в случае с контроллером articles, нам нужно добавить маршрут, чтобы Rails знал, по какому адресу мы хотим пройти, чтобы увидеть комментарии. Снова откройте файл config/routes.rb и отредактируйте его следующим образом:

Rails.application.routes.draw do
  root "articles#index"

  resources :articles do
    resources :comments
  end
end

Это создаст comments как вложенный ресурс в articles. Это другая сторона захвата иерархических отношений, существующих между статьями и комментариями.

Более подробно о роутинге написано в руководстве Роутинг в Rails.

Имея модель, обратим свое внимание на создание соответствующего контроллера. Снова будем использовать тот же генератор, что использовали прежде:

$ bin/rails generate controller Comments

Создадутся три файла и пустая директория:

Файл/Директория Назначение
app/controllers/comments_controller.rb Контроллер Comments
app/views/comments/ Вью контроллера хранятся здесь
test/controllers/comments_controller_test.rb Тест для контроллера
app/helpers/comments_helper.rb Хелпер для вью

Как и в любом другом блоге, наши читатели будут создавать свои комментарии сразу после прочтения статьи, и после добавления комментария они будут направляться обратно на страницу отображения статьи и видеть, что их комментарий уже отражен. В связи с этим, наш CommentsController служит в качестве средства создания комментариев и удаления спама, если такой будет.

Сначала мы расширим шаблон Article show (app/views/articles/show.html.erb), чтобы он позволял добавить новый комментарий:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

<h2>Add a comment:</h2>
<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

Это добавит форму на страницу отображения статьи, создающую новый комментарий при вызове экшна create в CommentsController. Тут вызов form_with использует массив, что создаст вложенный маршрут, такой как /articles/1/comments.

Давайте напишем create в app/controllers/comments_controller.rb:

class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end

Тут все немного сложнее, чем вы видели в контроллере для статей. Это побочный эффект вложения, которое вы настроили. Каждый запрос к комментарию отслеживает статью, к которой комментарий присоединен, таким образом сначала решаем вопрос с получением статьи, вызвав find на модели Article.

Кроме того, код пользуется преимуществом некоторых методов, доступных для связей. Мы используем метод create на @article.comments, чтобы создать и сохранить комментарий. Это автоматически связывает комментарий так, что он принадлежит к определенной статье.

Как только мы создали новый комментарий, мы возвращаем пользователя обратно на оригинальную статью, используя хелпер article_path(@article). Как мы уже видели, он вызывает экшн show в ArticlesController, который, в свою очередь, рендерит шаблон show.html.erb. В этом месте мы хотим отображать комментарии, поэтому давайте добавим следующее в app/views/articles/show.html.erb.

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

<h2>Comments</h2>
<% @article.comments.each do |comment| %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>

  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>
<% end %>

<h2>Add a comment:</h2>
<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

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

Статья с комментариями

Теперь, когда у нас есть работающие статьи и комментарии, взглянем на шаблон app/views/articles/show.html.erb. Он стал длинным и неудобным. Давайте воспользуемся партиалами, чтобы разгрузить его.

Сначала сделаем партиал для комментариев, показывающий все комментарии для статьи. Создайте файл app/views/comments/_comment.html.erb и поместите в него следующее:

<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>

<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>

Затем можно изменить app/views/articles/show.html.erb вот так:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

<h2>Comments</h2>
<%= render @article.comments %>

<h2>Add a comment:</h2>
<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

Теперь это отрендерит партиал app/views/comments/_comment.html.erb по разу для каждого комментария в коллекции @article.comments. Так как метод render перебирает коллекцию @article.comments, он назначает каждый комментарий локальной переменной с именем, как у партиала, в нашем случае comment, которая нам доступна в партиале для отображения.

Давайте также переместим раздел нового комментария в свой партиал. Опять же, создайте файл app/views/comments/_form.html.erb, содержащий:

<%= form_with model: [ @article, @article.comments.build ] do |form| %>
  <p>
    <%= form.label :commenter %><br>
    <%= form.text_field :commenter %>
  </p>
  <p>
    <%= form.label :body %><br>
    <%= form.text_area :body %>
  </p>
  <p>
    <%= form.submit %>
  </p>
<% end %>

Затем измените app/views/articles/show.html.erb следующим образом:

<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= link_to "Destroy", article_path(@article), data: {
                    turbo_method: :delete,
                    turbo_confirm: "Are you sure?"
                  } %></li>
</ul>

<h2>Comments</h2>
<%= render @article.comments %>

<h2>Add a comment:</h2>
<%= render 'comments/form' %>

Второй render всего лишь определяет шаблон партиала, который мы хотим рендерить, comments/form. Rails достаточно сообразительный, чтобы подставить подчеркивание в эту строку и понять, что Вы хотели рендерить файл _form.html.erb в директории app/views/comments.

Объект @article доступен в любых партиалах, рендерящихся во вью, так как мы определили его как переменную экземпляра.

Concerns — это способ упростить большие контроллеры или модели для лучшего понимания и управления. У этого также есть преимущество повторного использования, когда несколько моделей (или контроллеров) разделяют те же самые concerns. Concerns реализуются с помощью модулей, содержащих методы, представляющие четко очерченный срез функциональности, за которую ответственны модель или контроллер. В других языках модули часто называются миксинами (mixin).

В контроллере или модели concerns можно использовать так же, как вы бы использовали другой модуль. Когда вы только создали свое приложение с помощью rails new blog, среди прочего в app/ были созданы две папки:

app/controllers/concerns
app/models/concerns

В вышеприведенном примере мы реализуем новую особенность для нашего блога, которая будет использовать преимущества concern. Затем мы создадим concern и отредактируем код, чтобы он его использовал, что сделает код менее повторяемым и более поддерживаемым.

У статьи в блоге могут быть различные статусы — к примеру, она может быть видимой для всех (т.е. public) или только видимой для автора (т.е. private). Она также может быть скрытой, но все еще доступной (т.е. archived). Комментарии схожим образом могут быть скрытыми или видимыми. Это может быть представлено с помощью столбца status в каждой модели.

Сначала давайте запустим следующие миграции для добавления status в Articles и Comments:

$ bin/rails generate migration AddStatusToArticles status:string
$ bin/rails generate migration AddStatusToComments status:string

А затем давайте обновим базу данных с помощью сгенерированных миграций:

Чтобы выбрать статус для существующих статей и комментариев, можно добавить значение по умолчанию в сгенерированные файлы миграции, добавив опцию default: "public" и запустив миграции заново. Также можно вызвать в консоли rails Article.update_all(status: "public") и Comment.update_all(status: "public").

Также нужно разрешить ключ :status, как часть strong parameter, в app/controllers/articles_controller.rb:

  private
    def article_params
      params.require(:article).permit(:title, :body, :status)
    end

и в app/controllers/comments_controller.rb:

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body, :status)
    end

В модель article, после запуска миграции для добавления столбца status с помощью bin/rails db:migrate, можно добавить:

class Article < ApplicationRecord
  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }

  VALID_STATUSES = ['public', 'private', 'archived']

  validates :status, inclusion: { in: VALID_STATUSES }

  def archived?
    status == 'archived'
  end
end

и в модель Comment:

class Comment < ApplicationRecord
  belongs_to :article

  VALID_STATUSES = ['public', 'private', 'archived']

  validates :status, inclusion: { in: VALID_STATUSES }

  def archived?
    status == 'archived'
  end
end

Затем, в шаблоне экшна index (app/views/articles/index.html.erb) мы могли бы использовать метод archived?, чтобы избежать отображения любой архивированной статьи:

<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <% unless article.archived? %>
      <li>
        <%= link_to article.title, article %>
      </li>
    <% end %>
  <% end %>
</ul>

<%= link_to "New Article", new_article_path %>

Схожим образом в нашем партиале (app/views/comments/_comment.html.erb) мы могли бы использовать метод archived?, чтоб избежать отображения любого архивированного комментария:

<% unless comment.archived? %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>

  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>
<% end %>

Однако, если посмотреть на наши модели, можно заметить, что логика дублируется. Если в будущем мы улучшим функционал нашего блога — включим приватные сообщения, к примеру — мы можем снова начать дублировать логику. Вот тут-то и пригодятся concerns.

Concern ответственен только за конкретную часть ответственности модели; все методы нашего concern будут относиться к видимости модели. Давайте назовем новый concern (модуль) Visible. Можно создать новый файл в app/models/concerns с именем visible.rb, и хранить все методы статуса, которые продублированы в моделях.

app/models/concerns/visible.rb

module Visible
  def archived?
    status == 'archived'
  end
end

Также можно добавить наши валидации статуса в concern, но это немного сложнее, так как валидации — это методы, вызванные на уровне класса. ActiveSupport::Concern (руководство по API) предоставляет нам более простой способ включить их:

module Visible
  extend ActiveSupport::Concern

  VALID_STATUSES = ['public', 'private', 'archived']

  included do
    validates :status, inclusion: { in: VALID_STATUSES }
  end

  def archived?
    status == 'archived'
  end
end

Теперь можно убрать дублированную логику из каждой модели, а вместо нее включить наш новый модуль Visible:

В app/models/article.rb:

class Article < ApplicationRecord
  include Visible

  has_many :comments

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

и в app/models/comment.rb:

class Comment < ApplicationRecord
  include Visible

  belongs_to :article
end

Методы класса также можно добавить в concern. Если нам нужно отображать количество публичных статей или комментариев на главной странице, можно добавить метод класса в Visible следующим образом:

module Visible
  extend ActiveSupport::Concern

  VALID_STATUSES = ['public', 'private', 'archived']

  included do
    validates :status, inclusion: { in: VALID_STATUSES }
  end

  class_methods do
    def public_count
      where(status: 'public').count
    end
  end

  def archived?
    status == 'archived'
  end
end

Затем во вью его можно вызвать как любой другой метод класса:

<h1>Articles</h1>

Our blog has <%= Article.public_count %> articles and counting!

<ul>
  <% @articles.each do |article| %>
    <% unless article.archived? %>
      <li>
        <%= link_to article.title, article %>
      </li>
    <% end %>
  <% end %>
</ul>

<%= link_to "New Article", new_article_path %>

Наконец, добавим список выбора в формы и разрешим пользователю выбирать статус при создании новой статьи или публикации нового комментария. Также можно указать статус по умолчанию как public. В app/views/articles/_form.html.erb можно добавить:

<div>
  <%= form.label :status %><br>
  <%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</div>

и в app/views/comments/_form.html.erb:

<p>
  <%= form.label :status %><br>
  <%= form.select :status, ['public', 'private', 'archived'], selected: 'public' %>
</p>

Другой важной особенностью блога является возможность удаления спама. Чтобы сделать это, нужно вставить некоторую ссылку во вью и экшн destroy в CommentsController.

Поэтому сначала добавим ссылку для удаления в партиал app/views/comments/_comment.html.erb:

<% unless comment.archived? %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>

  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>

  <p>
    <%= link_to "Destroy Comment", [comment.article, comment], data: {
                  turbo_method: :delete,
                  turbo_confirm: "Are you sure?"
                } %>
  </p>
<% end %>

Нажатие этой новой ссылки «Destroy Comment» запустит DELETE /articles/:article_id/comments/:id в нашем CommentsController, который затем будет использоваться для нахождения комментария, который мы хотим удалить, поэтому давайте добавим экшн destroy в наш контроллер (app/controllers/comments_controller.rb):

class CommentsController < ApplicationController

  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end

  def destroy
    @article = Article.find(params[:article_id])
    @comment = @article.comments.find(params[:id])
    @comment.destroy
    redirect_to article_path(@article), status: :see_other
  end

  private
    def comment_params
      params.require(:comment).permit(:commenter, :body, :status)
    end
end

Экшн destroy найдет статью, которую мы просматриваем, обнаружит комментарий в коллекции @article.comments и затем уберет его из базы данных и вернет нас обратно на просмотр статьи.

Если удаляете статью, связанные с ней комментарии также должны быть удалены, в противном случае они будут просто занимать место в базе данных. Rails позволяет использовать опцию dependent на связи для достижения этого. Модифицируйте модель Article, app/models/article.rb, следующим образом:

class Article < ApplicationRecord
  include Visible

  has_many :comments, dependent: :destroy

  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

Если вы опубликуете свой блог онлайн, любой сможет добавлять, редактировать и удалять статьи или удалять комментарии.

Rails предоставляет аутентификационную систему HTTP, которая хорошо работает в этой ситуации.

В ArticlesController нам нужен способ блокировать доступ к различным экшнам, если пользователь не аутентифицирован. Тут мы можем использовать метод Rails http_basic_authenticate_with, разрешающий доступ к требуемым экшнам, если метод позволит это.

Чтобы использовать систему аутентификации, мы определим ее вверху нашего ArticlesController в app/controllers/articles_controller.rb. В нашем случае, мы хотим, чтобы пользователь был аутентифицирован для каждого экшна, кроме index и show, поэтому напишем так:

class ArticlesController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]

  def index
    @articles = Article.all
  end

  # пропущено для краткости

Мы также хотим позволить только аутентифицированным пользователям удалять комментарии, поэтому в CommentsController (app/controllers/comments_controller.rb) мы напишем:

class CommentsController < ApplicationController

  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy

  def create
    @article = Article.find(params[:article_id])
    # ...
  end

  # пропущено для краткости

Теперь, если попытаетесь создать новую статью, то встретитесь с вызовом базовой аутентификации HTTP:

Вызов базовой аутентификации HTTP

После ввода правильного имени пользователя и пароля, вы останетесь аутентифицированным, пока не потребуется другое имя пользователя и пароль, или браузер будет закрыт.

Также для приложений на Rails доступны иные методы аутентификации. Двумя популярными дополнениями для Rails, среди прочих, являются Devise и Authlogic.

Безопасность, особенно в веб-приложениях, это обширная и детализированная область. Безопасность вашего приложения Rails раскрывается более детально в руководстве Безопасность приложений на Rails.

После того, как вы создали свое первое приложение на Rails, можете свободно его модифицировать и экспериментировать на свое усмотрение.

Помните, что вы не сможете сделать без посторонней помощи все, что угодно. Так же, как вы обращались к этому руководству «Rails для начинающих», далее можете так же свободно пользоваться этими ресурсами:

  • Ruby on Rails Guides
  • Ruby on Rails mailing list

Простейший способ работы с Rails заключается в хранении всех внешних данных в UTF-8. Если не так, библиотеки Ruby и Rails часто будут способны конвертировать ваши родные данные в UTF-8, но это не всегда надежно работает, поэтому лучше быть уверенным, что все внешние данные являются UTF-8.

Если вы допускаете ошибку в этой области, наиболее обычным симптомом является черный ромбик со знаком вопроса внутри, появляющийся в браузере. Другим обычным симптомом являются символы, такие как «Ã¼» появляющиеся вместо «ü». Rails предпринимает ряд внутренних шагов для смягчения общих случаев тех проблем, которые могут быть автоматически обнаружены и исправлены. Однако, если имеются внешние данные, не хранящиеся в UTF-8, это может привести к такого рода проблемам, которые не могут быть автоматически обнаружены Rails и исправлены.

Два наиболее обычных источника данных, которые не в UTF-8:

  • Ваш текстовый редактор: Большинство текстовых редакторов (такие как TextMate), по умолчанию сохраняют файлы как UTF-8. Если ваш текстовый редактор так не делает, это может привести к тому, что специальные символы, введенные в ваши шаблоны (такие как é) появятся как ромбик с вопросительным знаком в браузере. Это также касается ваших файлов перевода i18N. Большинство редакторов, не устанавливающие по умолчанию UTF-8 (такие как некоторые версии Dreamweaver) предлагают способ изменить умолчания на UTF-8. Сделайте так.
  • Ваша база данных: Rails по умолчанию преобразует данные из вашей базы данных в UTF-8 на границе. Однако, если ваша база данных не использует внутри UTF-8, она может не быть способной хранить все символы, которые введет ваш пользователь. Например, если ваша база данных внутри использует Latin-1, и ваш пользователь вводит русские, ивритские или японские символы, данные будут потеряны как только попадут в базу данных. Если возможно, используйте UTF-8 как внутреннее хранилище в своей базе данных.

Ruby on Rails Tutorial (3-е издание)
Изучение веб-разработки с Rails

Книга Ruby on Rails Tutorial научит вас разрабатывать настоящие веб-приложения на Ruby on Rails, веб-фреймворке с открытым исходным кодом на котором были написаны многие топовые сайты, такие как Twitter, Hulu, GitHub и Yellow Pages. Книгу Ruby on Rails Tutorial можно совершенно бесплатно читать онлайн; платными являются только PDF, EPUB и MOBI форматы.

Follow this book to receive email updates from the author.


Sorry, content not available

Время на прочтение
5 мин

Количество просмотров 54K

Ненадолго отставив серию статей о ЯП Ruby в сторону (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), решил презентовать вам новый цикл о фрэймворке Rails. Набравшись некоторого опыта в «обучении» попробую вывести эту серию на уровень качества и продуманности несколько выше, чем прежде.

Целью первой части уроков по Ruby on Rails будет создание некоторого многопользовательского блога (аля Хабр). Также хочется отметить, что для этой первой части желательно иметь познание о Руби хотя бы на уровне трех-четырех капель. Хочется поскорей приступить к кодингу, но начинать все равно придется с теории.

Что такое Ruby on Rails (далее RoR)? Самый распространненый ответ – это базирующийся на ЯП Ruby (далее Руби) фрэймворк, который реализует шаблон (далее паттерн) MVC. Выделим два главных пункта из ответа:

  • Это фрэймворк на базе Ruby
  • Он реализует паттерн MVC

Разберем каждый отдельно.

RoR – базирующийся на Руби фрэймворк

ЯП Руби – простой и мощный, возможность мета-программинга, блоков, итераторов, а также обработки исключений делает язык замечательной основой для фрэймворка. Собственно так и посчитал Дэвид Хэйнемеер Ханссон, создатель RoR, и в июле 2004 года фрэймворк вышел на свет.
Увидеть, как помогает мета-программирование Руби, можно увидеть в ORM компоненте RoR Active Record. Основываясь на имени класса, RoR считывает схему (schema) и налету создает объекты класса на базе таблицы БД. Можно перейти к следующему аспекту.

RoR реализует MVC

Возожно, вы уже слышали о MVC в отношении других фрэймворков, однако что представляет собой MVC в RoR? MVC – это паттерн архитектуры приложения, четко разделяющий три его компонента:

  • Model (далее Модель) является «сутью» приложения и отвечает за непосредственные алгоритмы, расчёты и тому подобное внутреннее устройство приложения. Также предоставляет линк к хранилищу данных.
  • View (Представление, дальше Вид) предназначен для вывода данных, предоставленных Моделью. Это единственная часть MVC, которая непосредственно контактирует с пользователем.
  • Controller (Поведение, далее Контроллер) получает данные от пользователя и передаёт их в Модель. Кроме того, он получает сообщения от Модели и передаёт их в Вид.

Вот схема MVC:
image
Исходя из этого RoR использует три компонента:

  • Active Record
  • Action View
  • Action Controller

Сочетание последних двух известно как Action Pack. Рассмотрим каждый компонент поближе, и узнаем, почему Руби так подходит для реализации фрэймворка.

Active Record

Active Record – это Модель в RoR. Модель хранит данные и предоставляет базу для работы с данными. Кроме этого Active Record также является ORM фрэймворком. ORM значит Object-relational mapping (Объектно-реляционная проекция). Собственно Active Record делает следующие вещи:

  • Проекция таблицы на класс. Каждая таблица проецируется на один или несколько классов по принципу convention over configuration (соглашение выше конфигурации). Одно из таких соглашений – имя таблицы должно быть во множественном числе, а название класса – в единственном. Атрибуты таблицы налету проецируются в атрибуты экземпляра Руби. После того, как все проекции сделаны, каждый объект ORM класса представляет определенную строку таблицы, с которой класс был спроецирован.
  • Соединение с БД. Вы можете подключиться к базе данных, используя API, предоставляемый Active Record, который создает необходимый вам запрос непосредственно в движок БД при помощи адаптеров. У Active Record есть адаптеры для MySQL, Postgres, MS SQLServer, DB2, и SQLite. Необходимо лишь записать параметры доступа к БД в файле database.yml.
  • Операции CRUD. Это операции create (создание), retrieve (получение), update (обновление) и delete (удаление) над таблицей. Так как Active Record – это ORM фрэймворк, вы всегда работаете с объектами. Чтобы создать новую строку таблицы, вы создаете новый объект класса и заполняете его переменные экземпляра значениями. Стоит заметить, что все это Active Record делает за вас.
  • Проверка данных. Проверка данных перед помещением их в таблицу – это первый шаг в безопасности вашего проекта. Active Record предоставляет проверку Модели. Данные могут быть проверены автоматически с помощью множества готовых методов, которые, в случае необходимости, можно переписать под собственные нужды.

Action View

Вид включает в себя логику, необходимую для вывода данных Модели. Роль Вида в RoR играет Action View. Наилее часто используемые функции Action View:

  • Шаблоны (Templates). Шаблоны – это файлы, содержащие заполнители (placeholders), которые буду заменены на контент. Шаблоны могут содержать HTML-код и код Ruby, встраиваемый в HTML с использованием синтакса встроенного (embedded) Ruby (ERb).
  • Помощники (helper, далее хелпер) форм и форматирования. Хелперы форм позволяют создавать такие элементы страниц, как чекбоксы, списки, используя готовые методы. В свою очередь хелперы форматирования позволяют форматировать данные необходимым нам способом, методы существуют для дат, валют и строк.
  • Макет. Макеты (layouts) определяют, как контент будет расположен на странице. Динамически создаваемая страница может содержать вложение из нескольких страниц, даже без использования таблиц и фрэймов, используя API Макета.

Action Controller

В веб-приложении Контроллер регулирует поток логики приложения. Он находится на границе программы, перехватывая все запросы, на основе которых он изменяет какой-то объект Модели и вызывает Вид, чтобы отобразить обновленные данные. В RoR Action Controller является Контроллером, вот его основные функции:

  • Поддержка сессий. Сессия – это период времени, проведенный пользователем на сайте. Его можно отследить с помощью cookie или объекта сессии. Cookie – небольшой файл, он не может содержать объекты, в отличие от объекта сессии.
  • Фильтрация. Бывают ситуации, когда необходимо вызвать определенный код, перед тем как исполнять логику Контроллера или после него, например, аутентификация пользователей, логирование событий, предоставление персонального ответа. Помогают в таких случаях фильтры, предоставляемые Action Controller. Существуют три основных фильтра: before, after и around. О них – позже.
  • Кэширование. Кэширование – это процесс, при котором наиболее запрашиваемый контент сохраняется в кэше, чтобы не было необходимости запрашивать его вновь и вновь.

Три среды

RoR поощряет использование отдельных сред для каждого из этапов цикла жизни приложения: разработка (development), тестирование (testing) и эксплуатация (production), для каждого из которых создается отдельная БД. Рассмотрим каждую среду.

  • development. В среде разработки ставка делается на немедленное отображение нового варианта при изменении кода – достаточно обновить страницу в браузере. Скорость в этой среде не важна. Когда случается ошибка, она выводится на экран.
  • test. При тестировании мы обычно каждый раз наполняем БД каким-нибудь глупым текстом, чтобы убедиться, что нормальное поведение не зависит от содержания БД. Процедуры юнит-тестинга и теста функциональности в RoR автоматизированы и производятся через консоль. Тестовая среда предоставляет отдельное пространство, в которых оперируют эти процедуры.
  • production. В конце концов ваше приложение выходит к финальной черте, пройдя тесты и избавившись от багов. Теперь обновления кода будут происходить редко и можно сконцентрироваться на производительности, включить кэширование. Нет необходимости писать огромные логи ошибок и пугать пользователей сообщениями об этих ошибках в браузере. Для вас – среда production.

Эпилог

Да, да, и тут эпилог — без него никуда ;) Сегодня мы с вами узнали о том, что такое MVC, как его реализуют Rails, узнали роль компонентов фрэймворка, узнали, как они сообщаются между собой. Взглянули даже на разные среды, которые предоставляют нам Rails. Если все понятненько, то можно начинать обустраивать рабочее место! Комментарии страстно желаемы ;)

PS: Этот номер написан по мотивам книги Building Dynamic Web 2.0 Websites with Ruby on Rails. Однако с литературой по Rails стоит быть максимально осторожным, поскольку фрэймворк развивается неуловимыми темпами, и почти все книги (даже 2008 г. выпуска, в том числе и эта) основана на старых версиях Rails (1.2.x)

В этом руководстве рассказывается о том,как вставать и работать с Ruby on Rails.

Прочитав этот путеводитель,вы узнаете:

  • Как установить Rails,создать новое приложение Rails и подключить приложение к базе данных.
  • Общий макет рельсового приложения.
  • Основные принципы MVC (модель,вид,контроллер)и RESTful дизайн.
  • Как быстро сгенерировать стартовые части приложения Rails.

Chapters

  1. Guide Assumptions
  2. Что такое Рейлс?
  3. Создание проекта «Новые рельсы
    • Installing Rails
    • Создание блог-приложения
  4. Hello, Rails!
    • Запуск веб-сервера
    • Скажи «Привет»,Рейлс
    • Настройка Главной страницы приложения
  5. Autoloading
  6. MVC и вы
    • Генерирование модели
    • Database Migrations
    • Использование модели для взаимодействия с базой данных
    • Отображение списка статей
  7. CRUDit там,где должен быть CRUDit
    • Показ отдельной статьи
    • Resourceful Routing
    • Создание новой статьи
    • Обновление статьи
    • Удаление статьи
  8. Добавление второй модели
    • Генерирование модели
    • Associating Models
    • Добавление маршрута для комментариев
    • Генерирование контроллера
  9. Refactoring
    • Рендеринг частичных коллекций
    • Отнесение частичной формы
    • Using Concerns
  10. Deleting Comments
    • Удаление связанных объектов
  11. Security
    • Basic Authentication
    • Другие соображения безопасности
  12. What’s Next?
  13. Configuration Gotchas

1 Предположения руководства

Это руководство предназначено для новичков,которые хотят приступить к созданию Rails-приложения с нуля.Оно не предполагает,что у вас есть опыт работы с Rails.

Rails-это фреймворк веб-приложений,работающий на языке программирования Ruby.Если у вас нет опыта работы с Ruby,вы найдете очень крутую кривую обучения погружения прямо в Rails.Существует несколько курируемых списков интернет-ресурсов по изучению Ruby:

  • Официальный сайт на языке программирования рубин
  • Список книг по свободному программированию

Имейте в виду,что некоторые ресурсы,хотя и остаются отличными,охватывают более старые версии Ruby и могут не включать синтаксис,с которым вы столкнетесь в повседневной разработке на Rails.

2 Что такое рельсы?

Rails-это фреймворк для разработки веб-приложений,написанный на языке программирования Ruby.Он предназначен для облегчения программирования веб-приложений,делая предположения о том,что необходимо каждому разработчику для начала работы.Он позволяет писать меньше кода,при этом достигая большего,чем многие другие языки и фреймворки.Опытные разработчики Rails также сообщают,что это делает разработку веб-приложений более увлекательной.

Железнодорожный является самоуверенным программным обеспечением.Оно делает предположение,что есть «лучший» способ делать вещи,и оно предназначено для того,чтобы поощрять этот способ-и в некоторых случаях препятствовать альтернативам.Если вы узнаете «The Rails Way»,вы,вероятно,обнаружите огромный рост производительности.Если вы будете продолжать привносить старые привычки других языков в разработку «Rails Way» и пытаться использовать шаблоны,которые вы выучили в другом месте,то,возможно,у вас будет меньше счастливого опыта.

Философия Rails включает в себя два основных руководящих принципа:

  • Не повторяйтесь : DRY — это принцип разработки программного обеспечения, который гласит, что «каждая часть знания должна иметь единственное, недвусмысленное и авторитетное представление в системе». Если не писать одну и ту же информацию снова и снова, наш код становится более удобным в обслуживании, более расширяемым и менее глючным.
  • Соглашение важнее конфигурации: Rails придерживается мнения о том, как лучше всего делать многие вещи в веб-приложении, и по умолчанию придерживается этого набора соглашений, а не требует, чтобы вы указали мелочи в бесконечных файлах конфигурации.

3 Создание проекта по строительству новых железных дорог

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

Следуя этому руководству, вы создадите проект Rails под названием blog , (очень) простой блог. Прежде чем вы сможете начать сборку приложения, вам необходимо убедиться, что у вас установлен сам Rails.

В приведенных ниже примерах $ используется для представления приглашения терминала в UNIX-подобной ОС, хотя оно могло быть настроено иначе. Если вы используете Windows, ваше приглашение будет выглядеть примерно так C:\source_code> .

3.1 Установка рельсов

Перед установкой Rails необходимо убедиться,что в вашей системе установлены необходимые предварительные условия.К ним относятся:

  • Ruby
  • SQLite3
  • Node.js
  • Yarn

3.1.1 Установка Ruby

Откройте командную строку. В macOS откройте Terminal.app; в Windows выберите «Выполнить» в меню «Пуск» и введите cmd.exe . Любые команды, перед которыми стоит знак доллара $ , следует запускать в командной строке. Убедитесь, что у вас установлена ​​текущая версия Ruby:

$ ruby 
ruby 2.7.0

Для работы Rails требуется Ruby версии 2.7.0 или более поздней.Предпочтительно использовать последнюю версию Ruby.Если возвращаемый номер версии меньше этого числа (например,2.3.7 или 1.8.7),вам необходимо установить свежую копию Ruby.

Чтобы установить Rails в Windows, вам сначала нужно установить Ruby Installer .

Чтобы узнать о других методах установки для большинства операционных систем, посетите ruby-lang.org .

3.1.2 Установка SQLite3

Вам также потребуется установка базы данных SQLite3. Многие популярные UNIX-подобные ОС поставляются с приемлемой версией SQLite3. Другие могут найти инструкции по установке на сайте SQLite3 .

Убедитесь, что он правильно установлен и в вашей загрузке PATH :

$ sqlite3 

Программа должна сообщить о своей версии.

3.1.3 Установка Node.js и Yarn

Наконец,вам потребуется установить Node.js и Yarn для управления JavaScript вашего приложения.

Найдите инструкции по установке на веб-сайте Node.js и убедитесь, что он установлен правильно, с помощью следующей команды:

$ node 

Должна быть выведена версия вашей среды выполнения Node.js.Убедитесь,что она больше,чем 8.16.0.

Чтобы установить Yarn, следуйте инструкциям по установке на веб-сайте Yarn .

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

$ yarn 

Если там написано что-то вроде «1.22.0»,значит,Yarn был установлен правильно.

3.1.4 Установка Rails

Чтобы установить Rails, используйте команду gem install , предоставленную RubyGems:

$ gem install rails

Чтобы убедиться,что все установлено правильно,вы должны быть в состоянии выполнить следующее в новом терминале:

$ rails 

Если там написано что-то вроде «Rails 7.0.0»,вы готовы продолжить.

3.2 Создание блог-приложения

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

Чтобы использовать этот генератор,откройте терминал,перейдите в каталог,где у вас есть права на создание файлов,и выполните команду:

$ rails new blog

Это создаст приложение Rails под названием Blog в каталоге blog и установит зависимости gem, которые уже упомянуты в Gemfile , с помощью bundle install .

Вы можете увидеть все параметры командной строки, которые принимает генератор приложений Rails, запустив rails new --help .

После создания блог-приложения переключитесь на его папку:

$ cd blog

В каталоге blog будет несколько сгенерированных файлов и папок, составляющих структуру приложения Rails. Большая часть работы в этом руководстве будет выполняться в папке app , но вот базовое изложение функций каждого из файлов и папок, которые Rails создает по умолчанию:

File/Folder Purpose
app/ Содержит контроллеры,модели,виды,помощники,почтовые службы,каналы,задания и активы для вашего приложения.В оставшейся части этого руководства вы сосредоточитесь на этой папке.
bin/ Содержит сценарий rails , запускающий ваше приложение, и может содержать другие сценарии, которые вы используете для настройки, обновления, развертывания или запуска вашего приложения.
config/ Содержит конфигурацию для маршрутов вашего приложения, базы данных и т. Д. Более подробно это описано в разделе «Настройка приложений Rails» .
config.ru Конфигурация стойки для серверов в стойке, используемых для запуска приложения. Дополнительные сведения о Rack см. На веб-сайте Rack .
db/ Содержит вашу текущую схему базы данных,а также миграции базы данных.
Gemfile
Gemfile.lock
Эти файлы позволяют указать, какие зависимости гема необходимы для вашего приложения Rails. Эти файлы используются гемом Bundler. Дополнительные сведения о Bundler см. На веб-сайте Bundler .
lib/ Расширенные модули для вашего приложения.
log/ Журнальные файлы приложений.
public/ Содержит статические файлы и скомпилированные активы.Когда ваше приложение запущено,эта директория будет открыта как есть.
Rakefile Этот файл находит и загружает задачи, которые можно запускать из командной строки. Определения задач определены во всех компонентах Rails. Вместо того, чтобы изменять Rakefile , вам следует добавлять свои собственные задачи, добавляя файлы в каталог lib/tasks вашего приложения.
README.md Это краткая инструкция по применению.Вы должны отредактировать этот файл,чтобы рассказать другим,что делает ваше приложение,как его настроить и так далее.
storage/ Файлы Active Storage для Disk Service. Это описано в обзоре Active Storage .
test/ Модульные тесты, приспособления и другое тестовое оборудование. Они описаны в разделе «Тестирование приложений Rails» .
tmp/ Временные файлы (например,кэш-память и pid-файлы).
vendor/ Место для всех сторонних кодов.В типичном приложении Rails это включает в себя обожаемые драгоценные камни.
.gitignore Этот файл сообщает git, какие файлы (или шаблоны) он должен игнорировать. См. GitHub — Игнорирование файлов для получения дополнительной информации об игнорировании файлов.
.ruby-version Этот файл содержит версию Ruby по умолчанию.

Знакомство с Rails[править]

Что входит в Rails?[править]

Rails — это полноценный, многоуровневый фреймворк для построения веб-приложений, использующих базы данных, который основан на архитектуре Модель-Представление-Контроллер (Model-View-Controller, MVC).
Динамичный AJAX-интерфейс, обработка запросов и выдача данных в контроллерах, предметная область, отраженная в базе данных, — для всего этого Rails предоставляет однородную среду разработки на Ruby. Все, что необходимо для начала — база данных и веб-сервер.

Кто пользуется Rails?[править]

Rails используют все — от стартапов и некоммерческих организаций до крупного бизнеса. Rails — это прежде всего инфраструктура, поэтому среда великолепно подходит для любого типа веб-приложений, будь это программы для организации совместной работы, поддержки сообществ, электронного бизнеса, управления содержанием, статистики, управления… Список можете продолжить сами.

Что еще нужно?[править]

Rails отлично работает со многими веб-серверами и СУБД. В качестве веб-сервера рекомендуется использовать Apache или nginx с модулем Phusion Passenger. Rails также можно разворачивать используя Unicorn, Thin, Mongrel или FastCGI. В качестве СУБД можно использовать MySQL, PostgreSQL, SQLite, Oracle, SQL Server, DB2 или Firebird. Использовать Rails можно на практически любой операционной системе, однако для развертывания мы рекомендуем системы семейства *nix.

Начало работы[править]

Инструменты[править]

Наверно существует столько вариантов разработки Rails приложений, сколько и Rails программистов. Но все они сводятся к двум вариантам: текстовый редактор/командная строка и интегрированная среда разработки (IDE).

Интегрированная среда разработки[править]

Дефицита в Rails IDE нет. Основные это: RadRails, RubyMine, 3rd Rail и NetBeans. Все кросс-платформенные, и некоторые из них очень хорошие, но в этом учебнике мы будем использовать связку текстовый редактор/командная строка.

Текстовые редакторы и командная строка[править]

Что мы используем для разработки Rails приложений, если нет шикарной IDE? Большинство Rails разработчиков выбирают по следующим критериям: использовать текстовый редактор для редактирования текста, а командную строку для выполнения команд. Комбинация зависит от ваших предпочтений и платформы:

Macintosh OS X: Многие разработчики на Rails предпочитают TextMate. Другие варианты — Emacs и MacVim (запускаемый командой macvim), великолепная мак-версия Vim. Также используют iTerm для терминала командной строки; другие превосходно довольствуются встроенным приложением Terminal.

Linux: Ваш выбор редактора основывается на описанном выше для OS X, за исключением TextMate. Мы рекомендуем графический Vim (gVim), gedit (с плагином GMate) или Kate. Что касается командной строки: каждый дистрибутив Линукс имеет по крайней мере одно заявленное приложение терминала командной строки (часто несколько).

Браузеры[править]

Хотя существует множество веб-браузеров, подавляющее большинство Rails разрабочиков используют Firefox, Safari или Chrome. Скриншоты в этом учебнике, как правило, будут в браузере Chrome. Если вы используете Firefox, предлагаем использовать Firebug, он позволяет динамическую проверку (и даже редактирование) структуры HTML и CSS правил на любой странице. Для тех, кто не использует Firefox, Firebug Lite работает с большинством других браузеров, таких как Safari и Chrome, и имеет встроенную «Проверку элемента». Независимо от того, какой браузер вы используете, опыт показывает, что время, потраченное на обучения подобным инструментам будет щедро вознаграждено.

По поводу инструментов[править]

В процессе приобщения ваше рабочее окружение будет установлено и запущено, вы возможно найдете что тратить много времени на приобщение ко всему будет правильно. Процесс обучения текстовым редакторам и IDE особенно долог; вы можете потратить неделю только на чтение руководства TextMate или Vim. Если Вы плохо знакомы с этим делом, я хочу уверить Вас, что расход времени на изучение инструментов нормален. Все проходят это. Иногда это печально и вызывает легкое беспокойство, когда у вас в голове уже есть веб-приложение и вы хотите только изучить Rails, но тратите неделю изучая некоторый таинственный древний редактор Unix только чтобы начать. Но мастер должен знать свои инструменты — в конце награда окупит усилия.

Ruby, RubyGems, Rails, and Git[править]

Классический способ установки из исходных текстов со страницы загрузки Ruby on Rails. Я предположу, что Вы можете перейти туда теперь; часть этой книги могут быть прочитаны с пользой без Сети, но не эта часть. Я только вставлю некоторые собственные комментарии к процедуре установки.

Установка Git[править]

Многое в экосистеме Rails зависит так или иначе от системы контроля версий называемой Git (описана в деталях в Разделе 1.3). Поскольку она повсеместно используется вы должны установить Git на этой ранней стадии; я предлагаю следовать инструкциям по установке Git для вашей системы в разделе Installing Git из Pro Git.

Установка Ruby[править]

Следующий шаг — установка Ruby. Возможно что он уже стоит в вашей системе, попробуем запустить:

$ ruby -v
ruby 1.9.2dev

Видим номер версии. Rails 3 требует Ruby 1.8.7 и выше, и отлично работает с Ruby 1.9.2. Этот учебник предполагает, что вы используете последную версию Ruby 1.9.2, известную как Ruby 1.9.2-head, но и с Ruby 1.8.7 должно быть всё хорошо.

Ветка Ruby 1.9 находится в интенсивной разработке, поэтому, к сожалению установка последней версии может быть нетривиальной задачей. Вам придётся полагаться на самые современные инструкции. Ниже приводится ряд шагов, после которых я привёл всё в рабочее состояние на моей системе (Macintosh OS X), но вам, возможно, придётся повозиться.

Как часть процедуры установки Ruby, если вы используете OS X или Linux, я настоятельно рекомендую устанавливать Ruby используя Ruby Version Manager (RVM), который позволяет устанавливать и управлять различными версиями Ruby на одной машине. (Проект Pik позволяет подобное при использовании Windows.) Это особенно важно, если вы хотите запускать Rails 3 и Rails 2.3 на одной машине. Если вы решили пойти этим путем, я рекомендую использовать RVM для установки двух комбинаций Ruby/Rails: Ruby 1.8.7/Rails 2.3.8 и Ruby 1.9.2/Rails 3.1.0. Если Вы сталкнётесь с какими-нибудь проблемами при использовании RVM, вы всегда можете найти его автора, Wayne Seguin, на канале IRC RVM (#rvm on freenode.net).8

После установки RVM Вы можете установить Руби следующим образом:

$ rvm install 1.9.2-head
<подождите немного>

Затем сделайте gemset для Rails 3, который позволит нам управлять отдельными пакетами gems если мы хотим (например) запускать Rails 2.3 на одной системе:

$ rvm gemset create rails3tutorial

Вы можете сделать эту версию и gemset версией по умолчанию следующим образом:

$ rvm use --default

Установка RubyGems[править]

RubyGems — это пакетный менеджер Ruby projects, и существуют тонны больших библиотек (включая Rails), доступных через пакеты Ruby или gems. Установка RubyGems должна быть лёгкой, так как Вы установили Ruby. Фактически, если Вы установили RVM, у Вас уже есть RubyGems, так как RVM включает его автоматически:

$ which gem
/Users/mhartl/.rvm/rubies/ruby-head/bin/gem

Если у Вас ещё нет этого, Вы должны загрузить RubyGems, распаковать его, и затем пойти в каталог rubygems и запустить программу установки:

$ [sudo] ruby setup.rb

Здесь sudo выполняет команду ruby setup.rb как администратор, который имеет доступ к файлам и каталогам, не доступным обычным пользователям; я поместил команду в скобках, чтобы указать, что использование sudo возможно не требуется для Вашей конкретной системы. Большинство Unix/Linux/OS X систем требуют sudo по умолчанию, если Вы не используете RVM как предложено в Разделе 1.2.2.2. Заметьте, что Вы не должны фактически печатать скобки; Вы должны запустить также

$ sudo ruby setup.rb

или

$ ruby setup.rb

в зависимости от вашей системы.

Если вы уже установили RubyGems ранее, то возможно вы захотите обновить вашу систему на последную версию:

$ [sudo] gem update --system

Установка Rails[править]

Установка Rails 3.0 может быть мудрёна, так как еще нет релиза и появляется много изменений. Вот команды, которые работали у меня:

[sudo] gem install rails --pre

Флаг «-pre» гарантирует, что вы получите пре-релиз версию Rails, которая на момент написания статьи стала релиз-кандидатом (rc)

Чтобы убедиться, в работе, запустите следующую команду:

$ rails -v
Rails 3.0.0.rc

Первое приложение[править]

Почти все приложения Rails генерируются с помощью команды rails. Это команда создает «скелет» будущего приложения в выбранном вами каталоге. Для начала создадим каталог для ваших Rails проектов, а затем запустим команду rails для генерации первого приложения:

$ mkdir rails_projects
$ cd rails_projects
$ rails new first_app
     create  
     create  README
     create  .gitignore
     create  Rakefile
     create  config.ru
     create  Gemfile
     create  app
     create  app/controllers/application_controller.rb
     create  app/helpers/application_helper.rb
     create  app/views/layouts/application.html.erb
     create  app/models
     create  config
     create  config/routes.rb
     create  config/application.rb
     create  config/environment.rb
     .
     .
     .

Заметьте сколько файлов и папок создает команда rails. Этот стандарт папок и файловой структуры является одним из многих преимуществ Rails, это сразу же продвигает вас от нуля до функционального (хоть и минимального) приложения. Кроме того, поскольку структура является общей для всех приложений Rails, вы можете без проблем разобраться в чужом коде.

Файл/Директория Описание
app/ Основные приложения (app) кода, включая модели, представления, контроллеры и помощники
config/ Конфигурация приложения
db/ Файлы для управления базой данных: схема базы данных и миграции
doc/ Документация приложения
lib/ Модули библиотек
log/ log файлы приложения
public/ Общедоступные файлы (например для веб-браузера)- изображения и каскадные таблицы стилей (CSS) и т.д.
script/rails/ Скрипт Rails для генерации кода, открытия консоли сессий, или запуск локального веб-сервера
test/ Юнит-тесты и прочий аппарат тестирования
tmp/ Временные файлы
vendor/ Сторонний код, например плагины и гемы
README/ Краткое описание приложения
Rakefile Утилиты задач, доступных через команду rake
Gemfile Gem требования для приложения
config.ru Файл конфигурации для Rack middleware
.gitignore Шаблоны для файлов, которые должны быть проигнорированы Git

Bundler[править]

После создания нового приложения Rails, следующий шаг заключается в использовании Bundler для установки и включения gems необходимых для приложения. Для этого откройте Gemfile с вашего любимого текстового редактора:

$ cd first_app/
$ mate Gemfile

Должно выйти что-то похожее:

 source 'http://rubygems.org'

 gem 'rails', '3.0.3'

 # Bundle edge Rails instead:
 # gem 'rails', :git => 'git://github.com/rails/rails.git'

 gem 'sqlite3-ruby', :require => 'sqlite3'

 # Use unicorn as the web server
 # gem 'unicorn'

 # Deploy with Capistrano
 # gem 'capistrano'

 # To use debugger
 # gem 'ruby-debug'

 # Bundle the extra gems:
 # gem 'bj'
 # gem 'nokogiri', '1.4.1'
 # gem 'sqlite3-ruby', :require => 'sqlite3'
 # gem 'aws-s3', :require => 'aws/s3'

 # Bundle gems for certain environments:
 # gem 'rspec', :group => :test
 # group :test do
 #   gem 'webrat'
 # end

Большинство из этих строк закомментированы с хэш-символа #; они здесь, чтобы показать вам некоторые наиболее часто используемых gems и привести примеры синтаксиса Bundler. Сейчас нам не потребуется каких-либо других gems, кроме тех, что по умолчанию: Rails, и gems для Ruby интерфейса базы данных SQLite.

Если вы укажете номер версии для gem команды, Bundler автоматически установит последнюю версию. К сожалению, gem обновления может привести к путанице и поломке, так что в этом уроке мы обычно включаем номер рабочей версии. Например, последняя версия sqlite3-ruby gem не будет установлен на OS X Leopard, в то время как предыдущая версия работает отлично. Просто для безопасности сделайте следующие исключения:

source 'http://rubygems.org'

gem 'rails', '3.0.3'
gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3'

Что заставит Bundler установить версию 1.2.5 от sqlite3-ruby gem. (Также мы удалили ненужные строки комментариев). Обратите внимание что если версия 1.2.5 от sqlite3-ruby gem у вас не работает, попробуйте версию 1.3.1.

Если вы работаете в Ubuntu Linux, вам может потребоваться установить несколько других пакетов на данный момент:

$ sudo apt-get install libxslt-dev libxml2-dev      # Linux only

Как только вы собрали надлежащий Gemfile, установите gems используя Bundle

$ bundle install
Fetching source index for http://rubygems.org/
.
.
.

Это может занять несколько минут, но когда это будет сделано наше приложение будет готово к запуску.

rails server[править]

Страница Rails по умолчанию

Благодаря запуску новых rails и установке bundle, у нас уже есть приложение, которое можно запустить, но как? К счастью, Rails поставляется с программной командной строкой или скриптом, который запускает локальный веб-сервер, видимый только на вашем компьютере.

$ rails server
=> Booting WEBrick
=> Rails 3.0.3 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server

Это говорит о том, что приложение работает на порту номер 3000 по адресу 0.0.0.0. Это специальный адрес означает, что с любого компьютера в локальной сети можно просматривать наше приложения, в частности, машина запускает сервер разработки, то есть локальную машину разработки — можете просматривать приложения, используя адрес localhost:3000. Мы можем увидеть результат посетив http://localhost:3000/

Чтобы просмотреть информацию о вашем приложении, нажмите на ссылку «About your application’s environment»

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

Модель-Представление-Контроллер (MVC)[править]

Схематическое представление архитектуры модель-представление-контроллер

На ранней стадии, полезно получить общие знания о работе Rails приложений. Вы уже заметили, что по умолчанию структура Rails приложения имеет app/ каталог с тремя подкатегориями: models, views, и controllers. Это намек на то, что Rails следует шаблону модель-представление-контроллер (MVC), который разделяет «domain logic» (или «business logic») от входной и представленной логикой, связанной с графическим пользовательским интерфейсом (GUI). В случае веб-приложений «domain logic» обычно состоит из data models для пользователей, статей, и продуктов, и GUI это только веб-страница в браузере.

При взаимодействии с приложением Rails, браузер посылает запрос, который получает веб-сервер и передаёт на Rails контроллер, который отвечает за то, что делать дальше. В некоторых случаях контроллер будет сразу генерировать шаблон, который конвертируется в HTML и отправляется обратно браузеру. Чаще всего для динамических сайтов, контроллер взаимодействует с моделью, которая является объектом Ruby. Ruby в свою очередь представляет элемент сайта (например, пользователя) и отвечает за связь с базой данных. После вызова модели, контроллер генерирует шаблон и возвращает полную веб-страницу в браузер как HTML.

Если это кажется немного абстрактным для вас, не беспокойтесь, мы будем часто возвращаться к этому разделу. Кроме того в будущем вы получите более подробное представление о MVC в контексте демо приложения. Наконец на последующих стадиях мы будем использовать все аспекты MVC.

Управление версиями с помощью Git[править]

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

Есть много вариантов для управления версиями, но Rails сообщество в значительной степени ориентировано на Git, систему управления версиями разработанной Линусом Торвальдсом для размещения ядра Linux.

Установка и настройка[править]

После установки Git, необходимо выполнить множество дополнительных шагов. Это системная установка, которая означает что вам необходимо сделать это на своем компьютере всего один раз:

$ git config --global user.name "Your Name"
$ git config --global user.email youremail@example.com 

Также используем более подробную команду проверки:

$ git config --global alias.co checkout

Это руководство использует полную команду checkout, которая работает на не сконфигурированных для сотрудничества системах, но обычно всегда используется git co для проверки проекта.

Последним этапом установки можно дополнительно задать текстовый редактор, который Git будет использовать для комментирования сообщений. При использовании графического редактора, например TextMate, gVim, или MacVim, вам необходимо убедиться в том что редактор прикреплен правильно:

$ git config --global core.editor "mate -w"

Замените «mate -w» на «gvim -f» для gVim или «mvim -f» для MacVim.

Установка первого репозитория[править]

Теперь мы подошли к тому, что вам необходимо проделывать каждый раз, как вы создаете новый репозиторий (в этой книге это случается всего один раз, но может быть вам понадобится это в будущем) Сперва перейдите в корневую директорию первого приложения и инициализируйте новый репозиторий:

$ git init
Initialized empty Git repository in /Users/mhartl/rails_projects/first_app/.git/

Следующим шагом является добавление файлов проекта в хранилище. Здесь есть несколько затруднений, например: по умолчанию Git записывает все изменения файлов, но есть некоторые файлы, которые мы не хотим отслеживать. Например, Rails создает файлы журнала для записи поведения приложения; эти файлы часто меняются, и нам не нужно, чтобы наша система управления версиями обновляла их постоянно. Git имеет простой механизм, чтобы игнорировать такие файлы: просто включите файл .gitignore в корневой каталог Rails с некоторыми правилами для Git — какие файлы нужно игнорировать.

Rails по умолчанию создает в корневой директорию .gitignore файл следующего содержания:

.bundle
db/*.sqlite3
log/*.log
tmp/**/*

В этом листинге прописаны файлы которые Git будет игнорировать, это — log файлы, временные Rails (tmp) файлы и SQLite база данных. Большинство из этих файлов часто автоматически изменяются, поэтому их неудобно включать в систему управления версиями.

Данных игнорируемых файлов в .gitignore файле вполне достаточно для этого учебника, но в зависимости от вашей системы вы можете использовать следующий листинг. Он также игнорирует файлы документации Rails, Vim и Emacs файлы подкачки, и (для OS X пользователей) .DS_Store каталоги созданные mac Finder приложением. Если вы хотите использовать этот листинг, то просто откройте .gitignore файл в вашем любимом текстовом редакторе и заполните его следующим содержанием:

.bundle
db/*.sqlite3*
log/*.log
*.log
tmp/**/*
tmp/*
doc/api
doc/app
*.swp
*~
.DS_Store

Добавление и фиксирование[править]

Наконец, мы добавим файлы в новый проект Rails на Git а затем зафиксируем результат. Вы можете добавить все файлы (кроме тех, которые соответствуют шаблонам игнорирования в gitignore.) Следующим образом:

$ git add .

Здесь точка ‘.’ представляется текущим каталогом, и Git достаточно умен, чтобы добавлять файлы рекурсивно, поэтому он автоматически включает все подкаталоги. Эта команда добавляет файлы проекта на промежуточный уровень, в котором они содержатся до изменения в вашем проекте, вы можете увидеть, какие файлы находятся на промежуточном уровне используя команду:

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   README
#       new file:   Rakefile
.
.
.

Результат на самом деле длинный, и здесь вертикальные точки это пропущенные строки.

Чтобы сообщить Git, что вы хотите сохранить изменения, используете следующую фиксирующую команду:

$ git commit -m "Initial commit"
[master (root-commit) df0a62f] Initial commit
42 files changed, 8461 insertions(+), 0 deletions(-)
create mode 100644 README
create mode 100644 Rakefile
.
.
.

Где -m позволяет добавить комментарий для фиксирования, если вы опустите -m, то Git откроет редактор, который вы указали в качестве стандартного и даст вам ввести там комментарий.

Важно запомнить что Git фиксация локальна, записывается только на ваш компьютер. Это в отличие от другой системы управления, под названием Subversion, в которой обязательно вносятся изменения на удаленном хранилище. Git в отличие от стиля Subversion, делает это двумя логическими частями: локальная запись изменений (git commit), и отправка изменения на удаленное хранилище (git push). В дальнейшем мы увидим пример отправки.

Тем временем вы можете увидеть ваши зафиксированные записи используя log команду:

$ git log
commit df0a62f3f091e53ffa799309b3e32c27b0b38eb4
Author: Michael Hartl <michael@michaelhartl.com>
Date:   Thu Oct 15 11:36:21 2009 -0700
  Initial commit

Для того, чтобы выйти из Git журнала нажмите q.

Так чем, все-таки, так хорош Git?[править]

Это наверно не совсем ясно, почему, включив в ваш проект систему управления версиями, вы получите выгоду. Так что давайте рассмотрим один пример. Предположим, вы сделали несколько случайных изменений, таких как (Ох!) удаление важного app/controllers/ каталога:

$ ls app/controllers/
application_controller.rb
$ rm -rf app/controllers/
$ ls app/controllers/
ls: app/controllers/: No such file or directory

Мы применяем Unix ls команды для листинга каталога app/controllers/ и команду rm для того чтобы удалить его. -rf означает «рекурсивную силу», которая рекурсивно удаляет все файлы, каталоги, подкаталоги и так далее, не требуя подтверждения на каждое удаление.

Посмотрим, что получилось:

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    app/controllers/application_controller.rb
#
no changes added to commit (use "git add" and/or "git commit -a")

Мы видим что было удалено несколько файлов, однако изменения коснулись только «рабочего дерева», они еще не были зафиксированы. Это означает, что мы можем легко отменить изменения с помощью Git, выполнив проверку предыдущей фиксации специальной командой (где -f означает перезапись всех изменений):

$ git checkout -f
$ git status
# On branch master
nothing to commit (working directory clean)
$ ls app/controllers/
application_controller.rb

Удаленные файлы и папки восстановлены!

GitHub[править]

Теперь, когда мы включили наш проект в систему контроля версиями Git, пришло время отправить ваш код до GitHub, специальный ресурс для кода, оптимизированный для размещения и обмена Git репозиториями. Копируя ваш репозиторий на GitHub мы преследуем две цели: полное резервное копирование кода (включая полную историю фиксаций), и упор на последующее более легкое сотрудничество. Этот шаг не является обязательным, но будучи членом GitHub вам открыты двери к участию разнообразных Ruby and Rails проектов. (GitHub очень хорошо принимает Ruby and Rails, в самом деле он написан на нём).

GitHub имеет целый список платных услуг, но на открытый исходный код их услуги бесплатны, поэтому создайте бесплатный GitHub аккаунт если у вас его еще нет. (Для начала прочитайте о SSH ключах) После регистрации щелкните по созданию хранилища и заполните его информацией. После заполнения формы, загрузите ваше первое приложение следующим образом:

$ git remote add origin git@github.com:<username>/first_app.git
$ git push origin master

Эти команды значат, что вы добавляете GitHub как зеркало для основного филиала, а затем загружаете ваше хранилище на GitHub. Просто замените <username> на ваше имя пользователя. Например:

$ git remote add origin git@github.com:railstutorial/first_app.git

Результат должен незамедлительно отобразиться на вашей странице в GitHub.

Отделение, редактирование, фиксация, слияние[править]

Отделение[править]

Вы наверно заметили, что GitHub показывает содержимое файла README на главной странице хранилища. В нашем случае проект создан с помощью команды Rails, и поэтому файл README создался автоматически. Это не очень информативно, и поэтому мы первым делом изменим README, описав в нем наш проект. В процессе мы будем использовать такие функции как отделение, редактирование, фиксация, слияние.

С помощью Git удобно создавать ответвления, которые эффектно копируют репозиторий и мы можем делать изменения не затрагивая родительских файлов. В большинстве случаев родительский репозиторий это старшее ответвление, и мы можем создать новый репозиторий используя checkout с параметром -b:

$ git checkout -b modify-README
Switched to a new branch 'modify-README'
$ git branch
master
* modify-README

Вторая команда, git branch, просто список всех локальных ответвлений, а звездочка * определяет, какая ветвь в данное время активна. Обратите внимание, что git checkout -b modify-README вместе создают новую ветвь и переключаются на неё, как указано звёздочкой перед ответвление modify-README.

Полную цену ветвления вы узнаете когда мы будем работать над проектом с несколькими разработчиками, но ветви полезны даже для одного разработчика. В частности, главная ветвь изолирована от любых изменений, которые мы делаем с ветвью темы, так что даже если мы сделаем что то не так, мы всегда сможем отказаться от изменений, проверив главную ветвь и удалив ветвь темы. Мы сделаем это в конце раздела.

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

Редактирование[править]

После создания ветви темы, мы отредактируем его, чтобы сделать немного более подробным. Мне нравиться использовать язык разметки Markdown для этой цели, и если вы используете расширение файла .markdown, то GitHub автоматически отформатирует его для вас. Итак для начала мы используем Git версию Unix команды mv («move») для изменении имени:

$ git mv README README.markdown
$ mate README.markdown

,а затем заполним его следующим содержанием:

# Ruby on Rails Tutorial: first application
This is the first application for
[*Ruby on Rails Tutorial*]

Фиксирование[править]

В связи с изменениями, мы можем взглянуть на состояние нашей ветви:

$ git status
# On branch modify-README
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    README -> README.markdown
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   README.markdown
#

На данный момент, мы могли бы использовать git add . как раньше, но Git обеспечивает параметром -a как ярлык для совершения всех модификаций в существующих файлах:

$ git commit -a -m "Improved the README file"
2 files changed, 5 insertions(+), 243 deletions(-)
delete mode 100644 README
create mode 100644 README.markdown

Будьте осторожны при неправильном использовании параметра -a, если вы добавили какие либо новые файлы в ваш проект с момента последней фиксации, вам сначала необходимо использовать git add .

Слияние[править]

Теперь, когда мы закончили делать наши изменения, мы готовы объединить результаты обратно в нашей главной ветви:

$ git checkout master
Switched to branch 'master'
$ git merge modify-README
Updating 34f06b7..2c92bef
Fast forward
README          |  243 -------------------------------------------------------
README.markdown |    5 +
2 files changed, 5 insertions(+), 243 deletions(-)
delete mode 100644 README
create mode 100644 README.markdown

Заметим, что Git вывод включает часто в себя такие вещи как 34f06b7, которые связаны с внутренним представлении о Git репозитории. Ваши результаты будут отличаться в подробностях, но в целом должны соответствовать примеру выше.

После того, как вы объединили изменения, вы можете очистить ваши разветвления удалив ветвь темы используя git branch -d если вы закончили с ними:

$ git branch -d modify-README
Deleted branch modify-README (was 2c92bef).

Этот шаг является необязательным, и на самом деле довольно часто можно оставить topic branch нетронутым. Таким образом вы сможете переключаться между topic и master branches до тех пор пока вам это нужно.

Как уже отмечалось выше можно отказатьс от изменений в topic branches, в данном случае используя git bransh -D:

# For illustration only; don't do this unless you mess up a branch
$ git checkout -b topic-branch
$ <really screw up the branch>
$ git add .
$ git commit -a -m "Screwed up"
$ git checkout master
$ git branch -D topic-branch

В отличие от параметра -d, -D удалит ветвь даже если мы не объединяли их в изменениях.

Push[править]

Теперь, когда мы обновили файл README, мы можем загрузить изменения на GitHub, чтобы увидеть результат:

$ git push

Как и было обещано, GitHub красиво оформил формат нового файла используя Markdown.

Развертывание[править]

Даже на этой ранней стадии мы собираемся развернуть наше (по прежнему пустое) Rails приложение к производству. Этот шаг является необязательным, но раннее развертывание часто позволяет уловить любые проблемы на этапе разработки. Альтернатива — развертывание только после трудоемких усилий запечатанное далеко в среде разработки, часто приводит к страшной головной боли интеграции, когда наступает время обеда.

Средства развертывания Ruby кода появились в течение нескольких прошедших лет, и сейчас для этого есть несколько замечательных функций. Они включают приложения для хостов или виртуальных частных серверов Phusion Passenger (модуль для Apache и Nginx), полный комплекс услуг развертывания таких компаний, как Engine Yard и Rails Machine, и облако развертывания услуг, таких как Engine Yard Cloud и Heroku.

Мой любимый способ развертывания Rails — опция Heroku, платформа, построенная специально для развертывания Rails и других веб Ruby applications. Heroku делает развертывание Rails приложений до смешного простым, используя для получения исходного кода систему управления версиями Git. (Это еще одна причина для последующей установки Git шаги в разделе 1.3, если вы еще не сделали этого.) Оставшаяся часть этого раздела посвящена развертыванию нашего первого приложения для Heroku.

Установка Heroku[править]

После регистрации на Heroku, установите Heroku gem:

$ [sudo] gem install heroku

Как и с GitHub, при использовании Heroku вам необходимо создать SSH ключи, если вы до сих пор это не сделали, и затем указать Heroku ваш public key, чтобы вы смогли использовать Git для загрузки ваших приложений на их сервера:

$ heroku keys:add

Наконец, используем команду Heroku для того чтобы создать место на серверах Heroku, чтобы наше приложение ожило:

$ heroku create
Created http://severe-fire-61.heroku.com/ | git@heroku.com:severe-fire-61.git
Git remote heroku added

Да, и это все. Heroku команда создает новый поддомен только для нашего приложения доступный для немедленного просмотра. Там пока что ничего нет, так что давайте займемся развертыванием.

Развертывание. Шаг первый.[править]

Для развертывания на Heroku, первый шаг заключается в использовании Git для загрузки приложении на Heroku:

$ git push heroku master

Развертывание. Шаг второй.[править]

Нет никакого второго шага! Мы уже все сделали! Чтобы увидеть готовое приложение, вы можете посетить адрес который вы видели когда вы запускали heroku create. Вы также можете использовать команду Heroku, которая автоматически сделает это:

$ heroku open

После того как вы успешно запустили ваше приложение, heroku обеспечивает красивый интерфейс для администрирования и настройки приложения.

Команды Heroku[править]

Есть целая куча команд Heroku, и мы едва будем использовать их все в нашем учебнике. Давайте используем одну из них чтобы переименовать приложение:

$ heroku rename youname

Заключение[править]

Мы прошли долгий путь в этой главе: монтаж, установка среды разработки, управления версиями и развертывание.

Все, что осталось, это, знаете, на самом деле начать обучение Rails. Давайте начнем!

Ссылки[править]

  • Heroku Cloud Platform (англ.)
  • Перевод остальных глав этого учебника (рус.) оригинал — Ruby on Rails Tutorial (англ.)
  • Ruby on Rails на русском: RoR. Учебные статьи.

Понравилась статья? Поделить с друзьями:
  • Тэмп 4 тахометр руководство по эксплуатации
  • Мануал ниссан цефиро vq25dd
  • На какой стадии развития организации основным ее средством является жесткое руководство
  • Настойка календулы инструкция по применению наружно
  • Инструкцию по продаже товаров по образцам