Стаття українською. Ruby on Rails, STI and Active Record Associations (belongs_to)
З’явилась у мене задача — зберегти адрес клієнта. Штат, місто, вулиця. Звичайно можна піти простим шляхом — додати таблиці states, cities, streets — в них додати поля на кшталт:
id number
name string
parent_id number
і реалізувати це через зв’язок belongs_to. Але — в даному випадку це буде занадто, тому що можна простіше :)
Використаємо STI — Single Table Inheritance .
Що каже нам документація:
“Sometimes, you may want to share fields and behavior between different models. Let’s say we have Car, Motorcycle, and Bicycle models. We will want to share the color and price fields and some methods for all of them, but having some specific behavior for each, and separated controllers too.”
Тобто, коли, як в нашому випадку, нам потрібно зберігати однакові дані — не потрібно створювати багато таблиць, можна все покласти в одну.
Приступаємо до найсмачнішого, до кодінгу :)
Створюємо дефолтний проект.
rails new sti_example
Створюємо міграцію для базового класу AddressPart
rails generate model address_part type:string name:string
І створюємо три моделі — State, City, Street
bin/rails generate model state --parent=AddressPartbin/rails generate model city --parent=AddressPartbin/rails generate model street --parent=AddressPart
Загалом що ми маємо? Таблицю address_parts і чотири моделі — AddressPart, State, City, Street.
Спочатку перевіримо — працює чи ні.
rails db:migrate — Створили таблицю.rails c — відкрили консоль і додали тестові записи
State.create(name: ‘CA’)
City.create(name: ‘Sacramento’)
Street.create(name: ‘Ace Ct’)
тепер потрібно перевірити — що дані правильно збереглись в таблицю.
p ActiveRecord::Base.connection.exec_query(‘select * from address_parts’)
і що ми бачимо? в таблиці є три записи, в type — вказано що саме там зберігається.
Це добре. Але тепер потрібно зробити зв’язок parent-child для тих даних. Закриваємо консоль командою — exit. Видаляємо ті дані що є і створюємо ще одну міграцію.
rails db:reset — перестворили базу даних. а так як у нас там лише одна таблиця — то по суті ми просто почистили дані.rails generate migration add_parentid_to_address_part parentid:integerrails db:migrate
Тепер потрібно модифікувати моделі. Зовсім трохи :)
Тепер додаємо дані в таблицю. (знову ж — запустивши консоль rails)
state = State.create(name: ‘CA’)
city = City.create(name: ‘Sacramento’)
Зробимо зв’язок штата і міста.
state.city << city
street = Street.create(name: ‘Ace Ct’)
і додаємо цю вулицю в місто
city.street << street
Для чистоти експерименту — додамо це одне місто без вулиць і ще одну вулицю в Sacramento
street = Street.create(name: ‘Aerojet Dr.’)
city.street << street
city = City.create(name: ‘San Diego’)
state.city << city
і дивимось в таблицю що у нас вийшло
p ActiveRecord::Base.connection.exec_query(‘select * from address_parts’)
що ми тут бачимо.
У штата CA — є два child записи (з parrentid = 1) — це міста Sacramento і San Diego.
У міста Sacramento є два child записи (з parentid = 2) — це вулиці Aerojet Dr. та Ace Ct.
І є місто San Diego — у которого вулиць немає :)
Також у нас працюють всі зв’язки. Тобто — виконання наступних команд покаже нам структуру даних ( що саме покажуть команди — це вам домашня вправа :) )
state = State.first
p state
p state.city
p state.city.first.street
street = Street.first
p street
p street.city
p street.city.state
На цьому дякую що прочитали. Успішних вам проектів. А в наступній статті ми побалакаємо як за допомогою Faker gem — зробити собі трохи адресів.