Thumb

Занятие 1 - Быстрый старт. Базовые навыки.

Дата начала - 08 июня 2019 10:00

  1. Создание нового проекта
  2. Управление структурой базы данных.
  3. MVC в Rails.
  4. Загрузка картинок, постраничный вывод записей.

 

Запись занятия

Конспект

Описание задачи

Create/Read/Update/Delete - базовый набор операций для какого-либо объекта. Обычно на примере этих базовых операций и демонстрируются базовые возможности веб фреймворков. Например, давайте подумаем, какие задачи нам нужно решить для этого.

  1. Где-то в базе данных хранить эти объекты
  2. Написать прослойку для базы данных, которая позволит реализовать логику работы с конкретной таблицей
  3. Создать HTML формы для ввода и вывода данных
  4. Написать код, который получит данные из формы и засунет их в базу данных
  5. Сделать так, чтобы этот код запускался, когда пользователь введет определенный URL

Мы сейчас описали стандартный MVC для веб приложений. Пункт 2 - модель, 3 - Представление, 4 - контроллер, 5 - роуты. Если кто-то не сталкивался раньше с MVC и боялся этих страшных схем, то знайте - MVC это всего лишь договоренность о том, что у Вас код будет логически разделен на некие части. Кстати, вопреки заблуждениям, это не значит разные файлы. 

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

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

Заходим в папку проекта и запускаем сервер - rails s. Он запустится на 3000 порту и будет доступен по адресу http://localhost:3000 Можем проверить, должны увидеть стартовую страницу rails

Задание роутов

Мы хотим, чтобы наши проекты выводились по адресу http://localhost:3000/projects Если мы сейчас вставим этот адрес в браузер, то получим ошибку о том, что Rails не знает такой путь. Дело в том, что каждый URL который должен обрабатываться фреймворком, должен быть задан явно. Rails конечно позволяет задавать магические роуты, но этого лучше не делать. Роуты - первое место, которое дает хоть какое-то представление о проекте.     

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

Добавление роутов осуществляется в файле config/routes.rb


resources :projects

Что такое rake?

rake - это вспомогательная утилита, для того, чтобы писать команды (таски), на DSL. Эта штука нужна в основном только для разработчика. Она позволяет очень удобно писать разные вспомогательные скрипты, которые потом можно будет использовать при разработке, но которые не входят в веб приложение. Они в чем-то похожи на консольные утилиты. К примеру у вас на проекте сразу 3 базы данных. В самом начале разработки проекта часто бывает необходимо полностью очищать все эти базы. Вместо того, чтобы вводить каждый раз несколько команд, можно написать rake task который будет это делать. Мы в следующих уроках потренируемся как это делать, а пока вы будете пользоваться готовыми командами, которые дает вам Rails. С первой уже познакомились, еще парочку выучим сегодня, остальные можно посмотреть командой rake -T

Добавление контроллера

Философия Rails - это Convention over Configuration. Это значит что базовые, рутинные вещи мы не программируем, а конфигурируем, следуем базовым соглашениям. Например, сейчас мы видим ошибку о том, что не найден ProjectsController. Т.е. Задав роут resources :projects

app/comtrollers/projects_controller.rb

Давайте добавим файл но пока оставим его пустым. Смотрите, новая ошибка. Rails нашла файл, который называется согласно ее конвенциям, но не нашла в нем класса, который ожидала. Эта ошибка кстати очень часто приводит в ступор, потому что она результат опечатки. Запомните ее и если встретите - знайте, вы опечатались где-то. Не можете найти где - время прогуляться и немного отдохнуть.

Теперь давайте добавим класс ProjectsController < ApplicationController. Он будет унаследован от ApplicationController. Все контроллеры должны быть унаследованы от этого класса или его производных.


class ProjectsController < ApplicationController
end

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

  • Вывод списка проектов
  • Вывод одного проекта
  • Вывод формы для создания проекта
  • Само создание объекта
  • Вывод формы для редактирования объекта
  • Само редактирование объекта
  • Удаление объекта

Этим стандартным операциям соответствуют стандартные экшены - index, show, new, create, edit, update, destroy. Которые определяются через метод с соответствующим названием. Поэтому давайте добавим в наш класс метод


class ProjectsController < ApplicationController
  def index
  end
end

Добавление представления

Опять обновляем страницу и видим еще одну ужасную огромную ошибку - не найден файл такой-то, искалось там-то с какими-то форматами и билдерами.

Рельса говорит Вам, что не может найти представление. Т.е не может найти тот файл, в котором хранится HTML код для отображения проектов. Хотя мы вроде как не просили ее еще ничего отображать. Дело в том, что rails проверит, а пытались ли мы явно указать, какой файл использовать для вывода списка проектов. Если нет, она последует дальше согласно своим конвенциям и будет искать файлapp/views/projects/index.html.erb

Давайте разберемся подробнее, почему именно файл в этом месте
app/views/ - папка со всеми представлениями
projects/ - папка, соответствующая имени контроллера
index - имя экшена
.html - формат запроса. Все запросы из браузера по умолчанию имеют формат html. Но, если запрос делался через javascript со стороны клиента, то он будет иметь другой формат - JS, JSON, XML - xml и так далее. Т.е мы можем написать сколько угодно разных представлений для одних и тех же данных. Обратите внимание, что это формат запроса, а не код на котором написано представление. Многие тут путаются
.erb - интерпретатор шаблона. Если вы знаете PHP то знаете, что там можно PHP код мешать с HTML кодом. До того, как этого не было, можно было либо формировать HTML через строку, или использовать шаблонизаторы. Erb как раз и является шаблонизатором, который позволяет вставлять руби код в файлы. Но, для HTML его не используют, мы сегодня разберем почему. Новый шаблонизатор мы используем уже сегодня, а с работой с разными форматами познакомимся на следующих уроках.

Пока что давайте просто добавим файл представления и выведем там информацию о том, что тут будет список проектов.


<h1>Projects</h1>

Добавление модели

Вернемся в контроллер и допишем до конца экшен index.


class ProjectsController < ApplicationController
  def index
    @projects = Project.all
  end
end

Пока не обращаем внимание на переменную . Согласно конвенциям Для проектов модель будет называться Project - имя таблицы в единственном числе. Добавим саму модель, для этого в папке models создадим файл app/models/project.rb


class Project < ApplicationRecord
end

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

Миграции

Опять перезагружаем страницу и видим сообщение, что в нашей базе данных нет таблицы projects - т.е. Опять работает соглашение. Вам не надо объявлять имя таблицы в модели, rails сама построит имя этой таблицы в базе данных. Более того, рельса сама вытащит из базы данных структуру Вашей таблицы и сохранит ее внутри модели. Кроме того, она расширит модель новыми методами, согласно колонкам в таблице.

Чтобы программисты не тянули не пойми откуда SQL и сами не поддерживали структуру базы в актуальных состояниях, существует такой инструмент как миграция. 
Миграция - это такой механизм, который позволяет все время поддерживать БД в актуальных состояниях и, в случае если что-то пошло не так, откатывать эти состояния.
Миграция состоит из двух путей - UP и DOWN. Если вы хотите произвести какие-то изменения в БД, то кроме команд, которые меняют ее вверх до нужного состояния, обязательно нужно написать команду, которая при необходимости откатит базу в предыдущее состояние. Давайте посмотрим, как работает миграция.

Новая миграция создается командой:

rails generate migration create_projects

После этого проекте создается файл миграции, в папке db/migrate

Редактируем этот файл (объявляем столбцы, индексы и т.д.) и затем прогоняем миграцию командой:


class CreateProjects < ActiveRecord::Migration[5.2]
  def change
    create_table :projects do |t|
       t.string :title
       t.timestamps
    end
  end
end

rake db:migrate

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

rake db:rollback

Создадим пару проектов

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

Запускаем консоль

rails c


Project.create title: ‘Project #1’
Project.create title: ‘Project #1’

Для того чтобы выйти из консоли, используем команду exit.

Возвращаемся в браузер, перезагружаем страницу, больше никаких ошибок, но проектов так и нет.

Возвращаемся в представление и добавляем код вывода проектов


<h1>Projects</h1>

<ul>
  <% @projects.each do |project| %>

    <li><%= project.title %><</li>
  <% end %>
</ul>

Подробнее о роутах

Роутинг в Rails - объемная тема, которую так сходу не охватишь. Но, давайте разберемся в том, что есть. После запуска команды rake routes мы видим следующие результаты - HTTP метод, имя хелпера, URL и экшен контроллера, который этот код обрабатывает. Т.е это очень полезный инструмент, который помогает быстро разобраться в существующих маршрутах. Я его использую, чтобы подсмотреть имя хелпера для вложенных маршрутов.

Когда вы добавляете любой роут в config/routes.rb, rails автоматически генерирует новые методы для этого маршрута. У разных маршрутов могут быть одинаковые хелперы, но разный HTTP метод.

Кстати, если говорить более точно это не имя хелпера, а его префикс, из которого строится 2 хелпера name_path и name_url - относительный и абсолютный путь.

Helpers в Rails

Во вьюхах никакой логики быть не должно. Поэтому она помещается в хелперы. Также хелперы используются для того, чтобы построить, какой-то сложный HTML во избежание больших кусков кода, вы просто помещаете его в хелпер и он уже возвращает готовый HTML. Название хелпера соответственно описывает его назначение. В Rails есть стандартные хелперы, которые мы сейчас будем использовать. Кроме того, как мы только что узнали - еще есть генерируемые хелперы-роуты. Давайте этим воспользуемся

Хелпер link_to - невероятно мощный инструмент для построения ссылок. В rails не надо писать огромный a tag, нужно только заполнить значения. Чтобы добавить ссылку на форму добавления проекта, нужно написать всего лишь link_to 'New Project', new_project_url


<h1> <%= link_to 'New Project', new_project_url %>
<ul>
  <% @projects.each do |project| %>
    <li><%= project.title %></li>
  <% end %>
</ul>

Создание объекта

Для добавления нового объекта в базу данных нужно добавить в контроллер 3 метода.

1 Экшен для вывода формы


class ProjectsController < ApplicationController

 def index
   @projects = Project.all
 end 

 def new
   @project = Project.new
 end
end

Как видите, мы у модели Project вызвали метод new. Этот метод делает тоже самое, что и во всех других языках - создает новый экземпляр класса. Присваиваем инстанс переменной, для доступа в представлении.

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

  • Тег формы
  • Метод формы
  • URL формы
  • Если передаем файл - то еще 2 параметра
  • Дальше на каждое поле нужно прописать инпут
  • Кнопка сабмита

Давайте посмотрим как выглядит форма в Rails

app/views/projects/new.html.erb


<%= form_for @project do |f| %>
 <%= f.text_field :title %>
 <%= f.submit 'Save' %>
<% end %>

И это все. Это вот та магия rails о которой все говорят. Фреймворк сам зная тип объекта построит форме с нужным методом и адресом. Кроме того описание самих полей так же максимально просто.

Забегая наперед, скажу что так никто не пишет. Есть еще более мощные инструменты для написания форм. Ведь это же форма, просто форма, программист не должен тратить время на ее построение. Он должен тратить время на сложную логику ее обработки. И в этом все философия rails и языка ruby.

2 Экшен для обработки формы

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


class Project < ApplicationRecord
 validates :title, presence: true, length: {minimum: 3}
end

Теперь вернемся на нашу форму, и посмотрим какой HTML построил Rails. Как видите, имя инпута является вложенным. Т.е фреймворк достаточно умный, чтобы объединить все параметры проекта под один ключ project.

Теперь напишем простой код, для обработки формы


def create
  @project = Project.new project_params

  if @project.save
    redirect_to projects_path
  else
    render :new
  end
end

Мы точно так же создаем новый объект, но на создание еще и передаем данные из формы. Благодаря тому, что они собраны одним ключем, нет смысла присваивать каждое значение отдельно, это делается в одну строку.

Дальше, мы проверяем, можем ли мы сохранить эту запись. Запись не сохраняется, если она не валидна. Т.е если мы на форме введем заголовок - она сохранится, если не введем - не сохранится. И дальше логика простая - если мы сохранили запись. Перенаправляем пользователя на список всех проектов.

Если не сохранили - отображаем форму опять. Кстати, тут многие путаются, давайте сразу уточним. render :new не вызовет экшен new а просто отрендерит файл app/views/projects/new.html.erb

Давайте попробуем, что получится. Как видим, все еще ничего не работает.

3 Strong params

За удобство инициализации объекта параметрами формы нужно платить. Ведь это не безопасно, потому что можно подставить абсолютно любые поля с абсолютно любыми значениями. В rails 3 эта проблема решалась тем, что в модели прописывались attr_accessible. Т.е в модели явно задавался список полей, которые можно массово присвоить из формы. Типа, это безобидные поля. Но, есть же например формы в админке, у некоторых пользователей может быть расширенный доступ. Поэтому, начиная с rails 4 в каждом контроллере нужно явно разрешить параметры, которые он принимает.


class ProjectsController < ApplicationController

 def index
   @projects = Project.all
 end 

 def new
   @project = Project.new
 end

 def create
   @project = Project.new project_params

   if @project.save
     redirect_to projects_path
   else
     render :new
   end
 end

 private

 def project_params
   params.require(:project).permit(:title)
 end
end

require - означает что параметры обязательно должны быть сгруппированы по ключу projects

permit - задает список разрешенных параметров. Теперь у нас все работает

Обратите внимание, что метод project_params объявлен как private. Таким образом как бы объявляют что метод не является экшеном контроллера.

Редактирование объекта

Давайте напишем контроллер и представления для редактирования проектов.

app/views/projects/index.html.erb


<h1>Projects</h1>
<%= link_to 'New Project', new_project_url %>

<ul>
  <% @projects.each do |project| %>
    <li><%= project.title %> <%= link_to 'Edit', edit_project_path(project) %> </li>
  <% end %>
</ul>

Была добавлена ссылка на страницу редактирования link_to 'Edit', edit_project_path(project)

app/views/projects/edit.html.erb


<%= form_for @project do |f| %>
 <%= f.text_field :title %>
 <%= f.submit 'Save' %>
<% end %>

Форма редактирования является полной копией формы создания. Т.е. Rails сам знает какой сейчас процесс и куда в итоге отправлять данные.

app/controllers/projects_controller.rb


class ProjectsController < ApplicationController

 def index
   @projects = Project.all
 end 

 def new
   @project = Project.new
 end

 def create
   @project = Project.new project_params

   if @project.save
     redirect_to projects_path
   else
     render :new
   end
 end

 def edit
   @project = Project.find params[:id]
 end

 def update
   @project = Project.find params[:id]

   if @project.update project_params
     redirect_to projects_path
   else
     render :edit
   end
 end

 private

 def project_params
   params.require(:project).permit(:title)
 end
end 

Добавлены методы edit и update

Мы вместо того, чтобы строить новый объект - просто ищем его в базе данных, используя метод модели find

params[:id] берется из URL - это можно посмотреть запустив команду rake routes. Дальше все то же самое, что и при создании объекта, только в случае неудачи рендерим форму edit

Кстати, вы должны были заметить 2 вещи, касательно формы. Данные подставились автоматически. Форма точно такая же. Т.е. Рельса сама понимает, что в одном случае у Вас новый объект, значит данные нужно отправить на создание, а во втором случае - объект выбран из базы, значит его данные нужно отправить на редактирование. Ну разве это не круто?

Удаление объекта из базы

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


def destroy
  @project = Project.find params[:id]
  @project.destroy

  redirect_to projects_path
end

Кстати, есть особенность в построении ссылки. Так как все ссылки по умолчанию делают GET запрос, нам нужно явно указать метод DELETE

Делается это так - link_to 'Delete', project_path(project), method: :delete, data: {confirm: 'You Sure?'}


<h1>Projects</h1>
<%= link_to 'New Project', new_project_url %>

<ul>
  <% @projects.each do |project| %>
    <li><%= project.title %> <%= link_to 'Edit', edit_project_path(project) %> <%= link_to 'Delete', project_path(project), method: :delete, data: {confirm: 'You Sure?'} %> </li>
  <% end %>
</ul>

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

Пиши как PRO

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

У нас есть повторяющийся код

Поиск проекта перед его редактированием и удалением. Есть простой способ вынести его в одно место. Такой механизм в Rails называется before_action. Это простой механизм указания метода, который нужно выполнить до выполнения экшена и условий его выполнения.


class ProjectsController < ApplicationController
 before_action :find_project, only: [:edit, :update, :destroy]

 def index
   @projects = Project.all
 end

 def new
   @project = Project.new
 end

 def create
   @project = Project.new project_params

   if @project.save
     redirect_to projects_path
   else
     render :new
   end
 end

 def edit
 end

 def update
   if @project.update project_params
     redirect_to projects_path
   else
     render :edit
   end
 end

 def destroy
   @project.destroy

   redirect_to projects_path
 end

 private

 def project_params
   params.require(:project).permit(:title, :image)
 end

 def find_project
   @project = Project.find(params[:id])
 end
end

На что стоит обратить внимание:

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

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

Паршиалы

Кроме того у нас одинаковые формы. Очевидно, что их можно переиспользовать. Для этого в Rails есть механизм паршиалов. Имя паршиала должно начинаться с подчеркивания. Используется метод render знакомый нам из контроллера

app/views/projects/_form.html.erb



<%= form_for project do |f| %>
 <%= f.text_field :title %>
 <%= f.submit 'Save' %>
<% end %>

app/views/projects/new.html.erb


<h1>Create project </h1>
<%= render 'form', project: @project %> 

app/views/projects/edit.html.erb


<h1>Edit project - <%= @project.title %> </h1>
<%= render 'form', project: @project %> 

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

Гем simple_form

Стандартные хелперы rails для построения форм достаточно мощные, но есть более продвинутые инструменты. Это 2 гема - simple_form и formastic. Мы будем использовать simple_form

Для установки нового гема добавляем его в Gemfile

bundle install

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


<%= simple_form_for project, html: {novalidate: true} do |f| %>
 <%= f.input :title %>
 <%= f.submit 'Save' %>
<% end %>

В этот коротком примере нам нужно многое запомнить

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

По умолчанию он формирует HTML c браузерной валидацией. Мы ее отключаем, чтобы продемонстрировать возможности валидации Rails. Попробуйте ввести пустое значение заголовка. Или короче трех символов. Мы получим человеко читаемое сообщение об ошибке. Кроме того, если заглянуть в исходный HTML код мы увидим, что на ошибку повешен CSS класс, который позволит легко стилизовать сообщение.

Кроме того, гем сам вывел нам label поля. В нашем примере выше у нас его не было. Т.е если нормально называть поля в базе данных, автоматически построится нормальная форма.

ы будем использовать этот гем дальше и еще увидим достаточно примеров с использованием его возможностей.

Гем hamlit

Язык разметки HTML был придуман очень давно. И он чересчур избыточный и не наглядный, со всеми этими тегами и свойствами даже самая простая разметка выглядит очень монструозно. Поэтому в веб программировании уже давно используют шаблонизаторы и другие форматы, которые потом конвертируются в HTML. Самый удобный и быстрый шаблонизатор в мире ruby - HAML . Его можно добавить в проект 2мя способами - gem haml-rails и gem hamlit Последний появился совсем недавно и работает в несколько раз быстрее своего предшественника.

Помните, когда рельса не могла найти паршиал, она выводила довольно непонятное сообщение. Давайте еще раз на него посмотрим. Нам интересна часть про builders - это и есть те самые шаблонизаторы. Изменив расширение файла с erb на haml мы говорим рельсе использовать другой шаблонизатор. Для быстрой конвертации HTML => HAML можно использовать html2haml

app/views/projects/index.html.haml


%h1 Projects
= link_to 'New Project', new_project_url
%ul
 - @projects.each do |project|
   %li
     = project.title
     = link_to 'Edit', edit_project_path(project)
     = link_to 'Delete', project_path(project), method: :delete, data: {confirm: 'You Sure?' }
     

Паджинация объектов

Постраничный вывод записей, одна из самых часто встречаемых задач. В rails это делается ну очень просто

Добавляем в Gemfile гем kaminari

bundle install

Меняем код контроллера


def index
  @projects = Project.all.page(params[:page]).per(2)
end

Выводим страницы в представлении. В самый конец представления добавляем


= paginate @projects

Все, готово

Загрузка изображения

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

Для начала необходимо создать миграцию - rails generate migration add_image_to_projects:


class AddImageToProjects < ActiveRecord::Migration[5.2]
 def change
   add_column :projects, :image, :string
 end
end

В базе мы будем хранить только путь к картинке, сам же файл будем хранить отдельно

Так как все файлы в папке app подключаются рекурсивно, то необходимо создать отдельную папку uploaders. А в ней создать два файла base_uploader.rb и project_picture_uploader.rb.

Содержание файла app/uploaders/base_uploader.rb:


class BaseUploader < CarrierWave::Uploader::Base
 include CarrierWave::MiniMagick

 def store_dir
   subfolder = Rails.env.test? ? 'test/' : ''
   "system/uploads/#{subfolder}#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
 end

 def default_url
   ActionController::Base.helpers.asset_path 'fallback/' + [model.class.to_s.underscore, mounted_as, version_name, "default.jpg"].compact.join('_')
 end

 def extension_white_list
   %w(jpg jpeg png)
 end
end

Содержание файла app/uploaders/project_picture_uploader.rb:


class ProjectImageUploader < BaseUploader
 version :thumb do
   process resize_and_pad: [400, 400]
 end

 version :thumb_2x do
   process resize_and_pad: [800, 800]
 end
end

Здесь указывается, как необходимо обрабатывать загруженный файл. При загрузке на сервер будет генерироваться 2 версии: одна будет использоваться в админке, а другая будет показываться пользователям. Эти картинки будут доступны по имени версии, указанной здесь(admin_thumb и thumb).

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


class Project < ApplicationRecord
 validates :title, presence: true, length: {minimum: 3}
 mount_uploader :image, ProjectImageUploader
end

Это команда переопределяет стандартные, созданные Rails, геттеры и сеттеры, чтобы предоставить DSL для работы с картинкой.

Теперь осталось только добавить поле для картинки в форму:


<%= simple_form_for project, html: {novalidate: true} do |f| %>
 <%= f.input :title %>
 <%= f.input :image %>

 <%= f.submit 'Save' %>
<% end %>

Кстати, если кто уже делал загрузку картинок в других технологиях, знают что для загрузки файла в саму HTML форму нужно добавить специальные атрибуты. Рельса сама сделает это за вас, как только вы ей скажете что вам нужно поле с типом файл. Если кто-то не понимает о чем речь, посмотрите исходный код формы до и после добавления = f.input :image

Кстати, simple_form сам заметил что поле является картинкой, ну разве это не круто?

Теперь нам нужно разрешить в контроллере принимать параметр image


def project_params
  params.require(:project).permit(:title, :image)
end

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


%h1 Projects
= link_to 'New Project', new_project_url
%ul
 - @projects.each do |project|
   %li
     = image_tag project.image.thumb.url
     = project.title
     = link_to 'Edit', edit_project_path(project)
     = link_to 'Delete', project_path(project), method: :delete, data: {confirm: 'You Sure?'}

Заключение

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

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

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

Всем удачи, до встречи на следующих занятиях.

  • 90 days of learning
  • 12 badges
  • Certificate
  • 13 Participants

Домашняя работа