Работа с БД из кода
Sequel для выполнения запросов
Настало время для работы с SQL прямо из Ruby кода. Для того, чтобы это было возможно, необходимо установить библиотеку sequel
gem 'sequel', '~> 5.69'
Также СУБД бывают различные и каждая из СУБД предоставляет свой собственный API для различных языков программирования. В Ruby для работы с SQLite необходим дополнительный гем
Теперь мы можем получить доступ до Sequel в нашем коде.
Для того, чтобы начать посылать запросы, нам нужно установить соединение с базой данных:
require 'sequel'
DB = Sequel.connect('sqlite://shop.db') # указываем путь до файла БД относительно .rb файла
# Также можно использовать именованные параметры на основе Hash. В данном случае необходимо обязательно укзаать значение для adapter
# DB = Sequel.connect(adapter: :sqlite, user: 'user', password: 'password', host: 'host', port: port, database: 'database_name.db')
DDL операции
Sequel предоставляет нам удобный DSL (domain-specific language) для выполнения DDL операций. Например, так будет выглядеть операция для создания таблицы items:
# В качестве аргумента передает название таблицы в виде символа, а также блок кода
DB.create_table :items do
primary_key :id # внутри которого с помощью методов описываем нашу таблицу
column :manufacture, String, null: false
column :model, String, null: false
column :color, String, null: false
column :price, Integer null: false,
column :date_added, Time, null: false
end
В данном примере мы вызывали метод .column
в который передавали:
название колонки
класс Ruby, который имеет сопоставление с типами SQL
параметры, передаваемые в виде хэша
DML операции
После того как таблица создана, рассмотрим пример запроса для получения товаров стоимостью выше 10 000 рублей отсортированные по цене в порядке убиывания
table = DB[:items]
result = table
.where{price > 10_000} # создаем блок кода с передачей условия в него
.order(Sequel.desc(:price)) # вызываем метод для сортировки
p result # Получаем массив значений в виде хэша
Мы можем также добавлять значения в нашу таблицу:
table.insert(
manUfacture: "apple",
model: "Iphone 14",
color: "Red",
price: 120_000,
date_added: Time.now
)
Точно также как и удалять:
table.where{id == 1}.delete
Sequel как ORM
Чаще всего встречается использование ORM для работы с базой данных. ORM - Object Relational Mapping. По сути, это работа с таблицами как с Ruby объектами, где каждый атрибут объекта - атрибут таблицы. Давайте создадим такой класс для нашей таблицы items.
require 'sequel'
# Sequel обязывает нас называть наши классы как таблицы в единственном числе
# Он использует название класса для определния названия таблицы
# если нам нужно изменить это поведение,
# то необходимо наследоваться с использованием названия в качестве аргумента (Sequel::Model(:items))
class Item < Sequel::Model
end
Item.where{price > 10_000}.order(Sequel.desc(:price))
Важно при этом создать объект соединения с помощью Sequel.connect(...)
, так как при создании модели будет использоваться неявно(без использования переменной) ранее созданное соеднинение. Сначала создаем соединение, потом инициализируем модели с помощью require
.
Ассоциации
Кроме того, в моделях нам доступны ассоциации. Ассоциации позволяют одной модели ссылаться на другие в случае, если между ними есть связь в виде FK.
Рассмотрим основные связи:
many_to_one - ассоциация описывает отношение "многие к одному" между двумя таблицами в базе данных. Это означает, что одна запись в "родительской" таблице может быть связана с множеством записей в "дочерней" таблице, но каждая запись "дочерней" таблицы имеет связь только с одной записью из "родительской" таблицы.
Пример использования ассоциации many_to_one для двух таблиц: students
и classrooms
. Здесь один класс (classroom) может иметь много студентов (students), но каждый студент может быть только в одном классе.
Структура двух таблиц:
students
1
Alice
1
2
Bob
1
classrooms
1
Math Class
Объявление моделей с ассоциацией в Sequel:
class Student < Sequel::Model
many_to_one :classroom
end
class Classroom < Sequel::Model
one_to_many :students
end
Теперь вы можете получить класс (classroom) каждого студента с помощью ассоциации many_to_one:
student = Student.where(id: 1).first
classroom = student.classroom
puts classroom.name # Выводит: "Math Class"
В данном случае, ассоциация many_to_one позволила установить связь между таблицами таким образом, что для каждого объекта Student можно легко получить соответствующий объект Classroom
, без необходимости писать дополнительные SQL-запросы.
one_to_many - ассоциация описывает отношение "многие ко многим" между двумя таблицами в базе данных. Это означает, что одна запись в первой таблице может быть связана с несколькими записями во второй таблице, и наоборот, одна запись во второй таблице может быть связана с несколькими записями в первой таблице.
Для реализации такого отношения обычно используется третья таблица, называемая "связующей" (join) таблицей, которая содержит внешние ключи (foreign keys) для обеих таблиц и связывает их записи.
Пример использования ассоциации many_to_many для таблиц students
, courses
, и связующей таблицы enrollments
. Здесь один студент может быть записан на несколько курсов, и каждый курс может иметь несколько студентов.
Структура таблиц:
students
1
Alice
courses
1
Math
2
History
enrollments
1
1
1
2
Объявление моделей с ассоциацией в Sequel:
class Student < Sequel::Model
many_to_many :courses, join_table: :enrollments
end
class Course < Sequel::Model
many_to_many :students, join_table: :enrollments
end
Теперь вы можете получить все курсы, на которые записан студент, или все студенты, которые записаны на курс, с помощью ассоциации many_to_many:
student = Student.where(id: 1).first
courses = student.courses
courses.each { |course| puts course.name } # Выводит: "Math", "History"
course = Course.where(id: 1).first
students = course.students
students.each { |student| puts student.name } # Выводит: "Alice"
Таким образом, ассоциация many_to_many позволяет установить связь многие ко многим между двумя таблицами с использованием связующей таблицы, и предоставляет удобный способ получения и работы с этими связями на уровне объектов Ruby и моделей Sequel.
Обратите внимание на следующие правила и рекомендации по составлению названий таблиц, классов и ассоциаций в контексте таблиц базы данных и объектно-реляционного отображения, такого как Sequel:
Таблицы:
Обычно названия таблиц должны быть во множественном числе и в нижнем регистре (например,
students
, bo`oks).Используйте подчеркивания для разделения слов в названиях таблиц (например, book_authors, order_items).
Старайтесь делать названия короткими и ясными, чтобы они отражали назначение таблицы.
Классы и модели:
Имена классов и моделей должны быть в единственном числе и в формате CamelCase (например, Student, Book).
Каждое слово в имени класса должно начинаться с заглавной буквы и не содержать подчеркиваний (например, BookAuthor, OrderItem).
Ассоциации:
Названия ассоциаций
one_to_many
иmany_to_many
должны быть во множественном числе и в нижнем регистре, чтобы они соответствовали названиям таблиц (например,students
,books
).Названия ассоциации
many_to_one
должно быть в единственном числе и в нижнем регистре, чтобы оно соответствовали названию класса и модели в нижнем регистре (например,student
,book
).
В случае если названия классов или ассоциаций отличаются от названий таблиц или не выполняют какое-либо из выше перечисленных правил, то необходимо будет вручную проставлять нзавания классов/таблиц. В противном случае работать это не будет.
Задание university
Задание todo_api
Напишите используя Sinatra и Sequel приложение для работы со списком дел, которое:
Добавляет новое дело в базу данных
Изменяет дело по его идентификатору
Удаляет дело по его идентификатору
Показывает список дел постранично
Рекомендации:
Требований как должна выглядеть модель дела здесь нет, поэтому можете включить свою фантазию и придумать
Для того, чтобы модель Sequel могла бы быть преобразована в JSON, вам необходимо включить JSON сериализацию
Last updated