Статьи

Рубин для новичков: работа с DataMapper

Ruby — один из самых популярных языков, используемых в сети. Здесь мы начали новую сессию на Nettuts +, которая познакомит вас с Ruby, а также с отличными фреймворками и инструментами, которые сопровождают разработку на Ruby. Сегодня мы рассмотрим гемы DataMapper, чтобы начать работу с базой данных в Ruby.



DataMapper — это ORM: объектно-реляционное отображение. По сути, это библиотека, которая позволяет вам работать с вашей базой данных из объектно-ориентированного кода. В этом уроке нет абсолютно никакого SQL. Однако ORM использует обычную базу данных под прикрытием; Сегодня мы будем использовать sqlite3, но вы можете просто использовать другой адаптер для работы с MySQL, PostGresql или другой базой данных.

В « Пении с Синатрой — приложение Recall» Дэн Харпер познакомил вас с DataMapper. В этом уроке мы углубимся в работу с библиотекой.


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

  • sqlite3 : это драгоценный камень базы данных.
  • dm-core : это основная функциональность DataMapper.
  • dm-migrations : этот гем выполняет миграцию базы данных.
  • dm-validations : как вы уже догадались, это обеспечивает функциональность проверки данных.
  • dm-timestamps : помогает с метками времени записей базы данных.
  • dm-sqlite-adapter : это адаптер, который подключает DataMapper к вашей базе данных; здесь мы будем использовать sqlite, но вы можете использовать dm-postgres-adapter , dm-mysql-adapter или все, что вам подходит.

Как только вы установите все эти драгоценные камни (см. Последнюю главу, если вам нужно знать, как установить драгоценные камни ), мы готовы к работе.


Давайте начнем с создания базовой модели. Модели определены в классах. Однако сначала мы должны подключиться к нашей базе данных.

На самом деле, самое первое, что нам нужно — это наши библиотеки вверху нашего файла.

1
2
3
4
require ‘dm-core’
require ‘dm-timestamps’
require ‘dm-validations’
require ‘dm-migration’

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

1
DataMapper.setup :default, «sqlite://#{Dir.pwd}/database.db»

Первый параметр указывает DataMapper использовать адаптер по умолчанию для типа базы данных. Вторая ссылка / URL для базы данных. Поскольку мы используем sqlite, мы просто ссылаемся на файл базы данных. Обратите внимание, что нам не нужно создавать этот файл; DataMapper создаст его для нас.

Теперь мы готовы создать модель. Как вы знаете, это класс.

1
2
3
4
5
6
7
class User
    include DataMapper::Resource
     
    property :id , Serial
    property :username , String
    property :email , String
end

Первым шагом является включение модуля DataMapper::Resource . Это дает вам пользовательские методы, которые вы будете использовать в своем классе. Самый важный метод здесь — это property . Здесь мы используем его для создания трех разных свойств: идентификатора, имени пользователя и адреса электронной почты. Как видите, первым параметром property является символ, который является именем свойства. Второй тип. Вы понимаете String, конечно, но что такое серийный. Собственно, property :id, Serial — сокращение от DataMapper для первичного ключа; ‘serial’ — это автоинкрементное целое число. Это ваш первичный ключ!


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

1
2
DataMapper.auto_migrate!
DataMapper.auto_upgrade!

Разница здесь в том, что auto_migrate! очистит все данные из базы данных; auto_upgrade! методы пытается согласовать то, что уже есть в базе данных, с изменениями, которые вы хотите внести. Это работает так, что после вашего класса модели вы вызовете один из этих методов. Вы не хотите запускать auto_migrate! Конечно, каждый раз, когда вы загружаете модель, вы можете запустить auto_upgrade! на каждой перезагрузке в разработке. Я сделал это так в Синатре:

1
2
3
configure :development do
    DataMapper.auto_upgrade!
end

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


Теперь, когда у нас есть ноги с DataMapper, давайте поднимем нашу модель на другой уровень. Давайте начнем с отметок времени.

Нам dm-timestamps гем dm-timestamps , так почему бы не использовать его? Если мы добавим в модель свойства «create_at» и «updated_at», этот гем автоматически обновит эти поля.

Конечно, вам не нужно добавлять оба, если вы не хотите их.

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

1
2
3
4
5
6
7
8
9
class Post
    include DataMapper::Resource
 
    property :slug , String , key: true, unique_index: true, default: lambda { |resource,prop|
    property :title , String , required: true
    property :body , Text , required: true
    property :created_at , DateTime
    property :updated_at , DateTime
end

Мы здесь немного перемешиваем; наши ‘title’ и ‘body’ являются обязательными полями. Мы определяем свойство ‘slug’ в качестве первичного ключа и говорим, что это должен быть уникальный индекс. Не пугайтесь значения по умолчанию ‘slug.’ Конечно, вы можете просто использовать необработанное значение любого типа, которым принадлежит ваша собственность, но мы делаем что-то большее. В Ruby (и других языках) есть лямбды, о которых вы можете думать как о маленькой функции. Это то, что может принимать «параметры» и возвращать значение, как функция. Если мы используем лямбду в качестве значения свойства ‘default’, DataMapper передаст ему ресурс (или запись базы данных, с которой вы работаете) и само свойство (в данном случае, ‘slug’). Итак, здесь мы берем значение в resource.title (свойство title), помещаем его в нижний регистр и используем метод gsub ( например, g gobal), чтобы переключить каждый пробел на тире. Таким образом, что-то вроде этого:

1
«This is a Title»

Станет так:

1
«this-is-a-title»

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

1
{ :key => «value» }

Вы все еще можете сделать это в 1.9, и вам это нужно, если вы не используете символы в качестве ключей. Но, если вы используете символы в качестве ключей, вы можете сделать это вместо этого:

1
{ key: «value» }

По сути, вы просто перемещаете двоеточие до конца символа (без пробела!) И удаляете ракету.

В DataMapper вы можете многое сделать с проверкой, и вы можете прочитать все об этом здесь . Тем не менее, давайте посмотрим на основы.

Есть два способа сделать проверки; мы собираемся использовать метод, который добавляет ваши проверки в хэш опций. Для свойства email в модели User мы установим проверку формата:

1
property :email, String, format: :email_address

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

Давайте потребуем определенную длину пароля:

1
property :password, String, length: 10..255

Если вы не знакомы с обозначением 10..255, это диапазон Ruby. Мы говорим, что пароль должен быть длиной от 10 до 255 символов.

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

В модели User добавьте эту строку

1
has n, :posts

Затем, в модели Post, сделайте это:

1
belongs_to :user

В базе данных это добавляет свойство user_id к таблице user_id . На практике это действительно легко; мы увидим это в ближайшее время.

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

1
2
3
def username= new_username
    super new_username.downcase
end

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

Примечание. Согласно документации (см. Здесь и здесь ), мы должны иметь возможность сделать @username = new_username.downcase в методе выше. Это то, что я сделал в скриншоте, и, как вы знаете, это не сработало, как ожидалось. С момента записи скриншота я обнаружил, что документация неверна, и это super способ сделать это .


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

1
2
3
4
5
6
7
user = User.new username: «JoeSchmo», firstname: «Joe», lastname: «Schmo», email: «joe@schmo.com», password: «password_12345»
user.save
 
user = User.new
user.username = «Andrew»
# etc.
user.save

При использовании User#new необходимо вызвать метод save чтобы фактически поместить запись в базу данных. Если есть ошибка (помните эти проверки?), Метод save вернет false. Затем вы можете перейти к свойству errors чтобы увидеть ошибки; это объект DataMapper :: Validations :: ValidationsErrors, но вы можете перебирать ошибки с each методом.

1
2
3
user.errors.each do |error|
    puts error
end

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

1
User.create username: «joeschmo», firstname: «Joe», lastname: «Schmo», email: «joe@schmo.com», password: «password_!@#$%»

Бум: создан и сохранен!

Как насчет поиска записи в базе данных? Если вы знаете ключ нужной записи, просто используйте метод get:

1
2
3
User.get(1)
 
Post.get(«this-is-a-title»)

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

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

1
2
3
4
5
User.first firstname: «Andrew»
 
User.last( :lastname => «Schmo»)
 
User.all #gets all the post

С DataMapper вы можете сделать гораздо больше; проверьте документацию для больше! Нажмите на поле с вопросом, если у вас есть какие-либо вопросы.