Чистые определения ассоциаций с Ruby Sequel

Я использую Sequel Джереми Эвана для заполнения базы данных (SQLite) данными, которые я собираю с веб-страниц. База данных включает ряд отношений «многие ко многим», которые я выражаю с помощью ассоциаций. Связи создаются в определениях классов, которые всегда оцениваются при запуске скрипта. Важно отметить, что определения класса ассоциации должны иметь необходимые таблицы. Таким образом, методы создания таблиц должны находиться на верхнем уровне с определениями ассоциации. Вот пример:

module Thing
db = Sequel.Sqlite('data.sqlite')

db.create_table(:clients)
    String :client_id, :primary_key => true
    String :client_data
end

db.create_table(:orders)
    String :order_id, :primary_key => true
    String :order_data
end

db.create_table(:orders_clients)
    String :order_id
    String :client_id
    primary_key [:order_id,:client_id]
end

class Person < Sequel::Model
    unrestrict_primary_key
    many_to_many :orders
end

class Order < Sequel::Model
    unrestrict_primary_key
    many_to_many :orders
end
end

Прежде всего, я думаю, что это довольно грязное решение, поскольку вызовы моих методов и определения классов находятся в одном и том же пространстве имен. Если я попытаюсь разделить определения классов, я получу ошибку No database associated with Sequel::Model (что имеет смысл, но я хочу отложить оценку определений ассоциаций, имея их после вызовов таблицы, всякий раз, когда они могут произойти).

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

def create_tables_and_schema (database_name)
    db = Sequel.Sqlite(database_name)
    db.create_table... #three of those, as above

class Person < Sequel::Model
    unrestrict_primary_key
    many_to_many :orders
end

class Order < Sequel::Model
    unrestrict_primary_key
    many_to_many :orders
end
end

Я думаю, что необходим другой способ выражения табличных отношений.

Приветствуются любые предложения по подходу и стилю. Пожалуйста, попросите разъяснений, если объяснение сбивает с толку.


person ivan-k    schedule 01.08.2012    source источник


Ответы (1)


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

create_tables.rb:

DB.create_table(:clients)
  String :client_id, :primary_key => true
  String :client_data
end

DB.create_table(:orders)
  String :order_id, :primary_key => true
  String :order_data
end

DB.create_table(:orders_clients)
  String :order_id
  String :client_id
  primary_key [:order_id,:client_id]
end

модели.rb:

DB = Sequel.sqlite('data.sqlite')
require 'create_tables'

class Person < Sequel::Model
  unrestrict_primary_key
  many_to_many :orders
end

class Order < Sequel::Model
  unrestrict_primary_key
  many_to_many :orders
end

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

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

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

person Jeremy Evans    schedule 01.08.2012
comment
Это, безусловно, делает код чище. Думаю, мне просто придется иметь дело со своим глубоким страхом перед константами. Большое спасибо, и спасибо за замечательный проект. Sequel делает Ruby абсолютно неотразимой платформой. - person ivan-k; 01.08.2012