Tutorial для rails розробників (частина 1) - diary of madman


Tutorial для rails розробників (частина 1) - diary of madman

Одна з хороших речей в React це те, що він не вимагає додаткових залежностей, що робить його тим, що підключається з практично будь-який JS бібліотекою. Скориставшись цією функцією, ми збираємося включити його в наш Rails стек і побудувати frontend-powered додаток, або, якщо побажаєте, Rails вьюха на стероїдах.

макет додатки

У даній статті, ми будемо створювати з нуля маленьке додаток для відстеження витрат; кожен запис буде містити дату, заголовок і суму. Записи будуть ділитися на Кредит (Credit) якщо сума більше нуля і Дебет (Debit) в зворотному випадку. Ось макет проекту:


Tutorial для rails розробників (частина 1) - diary of madman

Підсумовуючи, в додатку будуть наступні кейси:

  • Коли користувач створює новий запис через горизонтальну форму, вона (запис) буде додаватися в таблицю з усіма записами
  • Користувач зможе через підрядник редагувати будь-який запис
  • Клік по будь-якій кнопці Delete буде видаляти пов'язану запис з таблиці
  • Додавання, редагування та видалення записів буде оновлювати суму в вікні на верху сторінки

створюємо додаток

Будь-який додаток починається з простих речей. Створимо наш додаток і назвемо його, наприклад, Accounts:

Я рекомендую використовувати RVM для управління версіями Ruby і для кожної програми окремий gemset, докладніше можна подивитися в цій статті.

Для UI нашого проекту буде використаний Twitter Bootstrap. Процес установки bootstrap трохи виходить з рамок даного how-to, ви можете встановити наприклад офіційний гем bootstrap-sass дотримуючись інструкції або використовувати rails-assets.

Коли наш проект инициализирован, потрібно додати в нього React. В даному записі ми будемо встановлювати офіційний гем react-rails бо будемо використовувати деякі круті фішки, реалізовані в даному геме, але є й інші способи виконати це завдання, наприклад все теже rails-assets або можна завантажити вихідні з офіційної сторінки і розмістити їх в паку javascrips.

Якщо ви до цього мали справу з Rails, то ви знаєте як легко додати гем в проект, додамо потрібний нам гем react-rails в Gemfile:

Потім, природно, встановлюємо нові геми:

Якщо після процесу установки ви загляньте в файл application.js то знайдете там три нові лінії:

створюємо ресурс

Ми створимо ресурс Record. який буде включати поля date. title і amount. Замість використання генератора scaffold. ми будемо використовувати генератор resource. тому що нам не знадобляться всі файли і методи, які створюються при ісползованія scaffold.

Чуть чуть магії і у нас буде готовий ресурс Record. що включає модель, контролер і маршрути. Залишається тільки створити базу даних і запустити міграції.

Додатково ви можете створити кілька записів в базі даних використовуючи rails console:

Не забудьте запустити сервер за допомогою команди rails s.
Ура! Тепер ми можемо кодувати.

Вкладені компоненти: список записів

Нашим першим завданням буде рендерить будь-які записи в таблиці. Для початку, потрібно створити екшен index в нашому контролері Records:

Далі, нам потрібно створити новий файл index.html.erb в папці app / views / records /. цей файл буде мостом між нашим Rails додатком і React компонентами. Щоб досягти цього ми будемо використовувати хелпер метод react_component. який отримує ім'я компонента React, який ми хочемо отрендеріть разом з даними які ми хочемо в нього передати.

Варто зазначити, що цей хелпер надається гемом react-rails і якщо використовувати інші способи інтеграції React в Rails додаток, то він не буде працювати.

C такою розміткою, react_ujs бачить що ми намагаємося рендерить React компонент і буде форматувати його, включаючи властивості, які ми передали через react_component. в нашому випадку вміст @records.

Кожен компонент повинен містити метод render. який буде відповідати за рендеринг самого себе. Цей метод повинен повертати екземпляр класу ReactComponent, в цьому випадку, коли React виконає ре-рендер, він (екземпляр) буде оброблений оптимальним шляхом (React виявляє існування нових вузлів шляхом створення віртуального DOM в пам'яті). В наведеному вище прикладі ми створили екзмеплярів h2, вбудований ReactComponent.

Інший спосіб форматувати ReactComponents всередині методу render через JSX синтаксис. Приклад коду вище еквівалентент наступного:

Я рекомендую, якщо ви працюєте з soffescript, використовувати синтаксис React.DOM замість JSX. тому що код буде вибудовуватися ієрархічно, як, наприклад, в haml. Однак, якщо ви інтегруєте React в існуючу програму з erb, ви можете реюзать вже існуючий код конвертуючи його в JSX.

Тепер оновимо сторінку в браузері.

Відмінно! Ми відрендерили наш перший компонент React. Тепер настав час для відображення наших записів (records).

Крім методу рендеринга, React компоненти мають здатність спілкуватися між собою і повідомляти свої статки, щоб визначити необхідний ре-рендеринг чи ні. Нам потрібно форматувати стану наших комопнентов і властивості з необхідними значеннями:

Метод getDefaultProps буде виставляти властивості нашого компонента в разі, якщо ми забули відправити будь-які дані при його ініціалізації, і метод getInitialState буде генерувати початковий стан наших компонентів. Тепер нам потрібно відобразити записи надані нам вьюха Rails.

Компонент Record буде відображати рядок таблиці містить осередки для кожного атрибута записи. Не хвилюйтеся про ці null у викликах React.DOM. *, Це означає що ми не відправляємо атрибути в компоненти. Тепер оновимо метод рендер в компоненті Records наступним кодом:

Ми створили таблицю з рядком заголовком і всередині тіла таблиці ми створили елемент Record для кожної існуючої записи. Іншими словами, ми угнездился вбудований і кастомний React компоненета. Круто так?

Щоб React не витрачав багато часу на оновлення нашого UI, при створенні елемента Record, разом з ним ми посилаємо ключ: record.id. Якщо ми так не зробимо, то побачимо попередження в консолі браузера (і швидше за все отримаємо головний біль в подальшому).



Ви можете подивитися на результуючий код цієї секції тут або тільки зміни тут.

Батько-Нащадок комунікація: Створення записів

Тепер коли ми відображаємо всі наявні записи, буде непогано додати форму для створення нових записів, давайте додамо цю фічу в наше React / Rails додаток. На початку, нам потрібно додати метод в наш Rails контролер (не забуваємо використовувати strongparams):

Нічого фантастичного, просто Bootstrap інлайн форма. Зверніть увагу як ми оголошуємо атрибут value для установки значення інпут і атрибут onChange щоб прив'язати метод обробника, який буде викликатися на кожне натискання клавіші. Метод обробника handleChange буде використовувати ім'я атрибута щоб визначити який інпут запустив подія і оновлювати соответсвтующее значення стану:

Ми використовуємо інтерполяцію рядків щоб динамічно визначати ключі об'єктів, еквівалент @setState title: e.target.value коли name одно title. Але навіщо нам використовувати @setState. Чому ми не можемо просто засетіть бажане значення для @state як ми зазвичай це робимо в регулярних JS об'єктах? Тому що @setState буде виконувати 2 дії:

  1. Оновлювати стану компонента
  2. Запускати перевірку / оновлення UI на основі нового стану

Дуже важливо тримати це в голові кожного разу коли ми використовуємо state всередині наших компонентів.

Давайте подивимося на кнопку submit. в самому кінці нашого методу render:

Ми визначили атрибут disabled зі значенням! @valid (). що означає що ми напишемо метод valid. який буде перевіряти що дані, передані користувачем, коректні.

Для простоти ми перевіряємо @state на порожні рядки. Таким чином, кнопка Create буде включатися і вимикатися в залежності від того чи є дані в полях.




Отже, коли у нас є контролер і готова форма, час відправляти наші нові записи на сервер. Нам потрібно подія для обробки форми, додамо атрибут onSubmit в нашу форму і handleSubmit метод (таким же чином ми обробляли подія onChange раніше):

Давайте розберемо новий метод підрядник:

  1. запобігаємо відправку html форми
  2. Пост (POST) дані нового запису на поточний URL
  3. колбек в разі успіху (success callback)

Success callback це головна частина процесу, після успішного створення нового запису ми будемо повідомлені про цю подію і state відновиться в своє дефолтний значення. Пам'ятайте я згадував що компоненти спілкуються між собою через @props? Ось, це воно. Наш поточний компонент відправляє дані назад в батьківський компонент через @ props.handleNewRecord щоб повідомити його про існування нового запису.

Як ви вже здогадалися, всюди де ми створюємо елемент RecordForm нам потрібно передавати властивість handleNewRecord c повертає методом, щось на зразок React.createElement RecordForm, handleNewRecord: @addRecord. У нашого батьківського компонента Records є стан з усіма існуючими записами, нам потрібно оновити його згідно доданої записи.

Додамо новий метод addRecord в файлі records.js.coffee і створимо новий елемент RecordForm. відразу після заголовка h2 (всередині методу render)

Оновлення вкладку, заповніть форму новим записом і натисніть Create ... Ніяких затримок, запис додалася негайно і форма очистилася після сабмита, поновіть сторінку знову, щоб переконатися що бекенд зберіг нові дані.


Tutorial для rails розробників (частина 1) - diary of madman

Якщо ви використовували інші JS фреймворки з Rails (наприклад AngularJS) щоб реалізувати схожі функції, ви могли зіткнутися з проблемою відлупцював вашого POST запиту бо він не містить CSRF токен, який вимагає Rails. Чому ми не зіткнулися з цим зараз? Все просто, ми використовуємо jQuery щоб спілкуватися з бекендом, і jquery_ujs драйвер буде додавати CSRF токен в кожен AJAX запит за нас. Круто!

Ви можете подивитися на результуючий код цієї секції тут або тільки зміни тут.

Реюзабельние компоненти: Індикатори залишку

Яке додаток може бути без (милих) індикаторів? Давайте додамо блоки у верхній частині з корисною інформацією. Наша мета - показувати 3 значення: кількість кредитних коштів (total credit), кількість дебетових засобів (total debit) і баланс (balance). Здається що це робота для 3 компонентів або, може бути, для одного але з властивостями?

Ми використовуємо елемент Bootstrap - панель, щоб відображати інфорамцію блоками і встановлювати колір через властивість type. Ми також додали простий форматтер - amountFormat, який читає властивість amount і відображає його в форматі валюти.

По хорошому, щоб мати закінчену рішення, нам потрібно створити такий елемент (3 рази) всередині нашого основного компонента і відправляти в нього необхідні властивості в залежності від того що ми хочемо відобразити. Давайте спочатку зробимо метод калькулятор, відкриємо компонент Records і додамо наступні методи:

credits підсумовує всі записи зі значенням більше 0, debits - підсумовує всі записи зі значенням менше нуля і balance говорить сам за себе. Тепер, коли методи обчислювачі на місці, нам просто потрібно створити елементи AmountBox всередині методу render (відразу над компонентом RecordForm)

Ми закінчили з цією фішкою! Оновлення сторінку в браузері, ви повинні побачити три блоки, отобаржющіе суми, які ми вирахували раніше. Але стривайте! Є ще дещо! Додайте новий запис і подивіться що станеться ...


Tutorial для rails розробників (частина 1) - diary of madman

Ви можете подивитися на результуючий код цієї секції тут або тільки зміни тут.

замість висновку

Так як матеріал виходить досить об'ємним, я вирішив розділити його на дві частини і це перша:

Друга частина буде про setState / replaceState. видалення і редагування записів, рефакторинг і Reactive Data Flow.

Поділитися