Как лучше всего засеять базу данных в Rails?

82

У меня есть задача rake, которая заполняет некоторые исходные данные в моем приложении rails. Например, страны, штаты, операторы мобильной связи и т. Д.

Теперь у меня есть несколько операторов create в файлах в / db / fixtures и задача rake, которая их обрабатывает. Например, у меня есть одна модель - это темы. У меня есть файл theme.rb в / db / fixtures, который выглядит так:

Theme.delete_all
Theme.create(:id => 1, :name=>'Lite', :background_color=>'0xC7FFD5', :title_text_color=>'0x222222',
                      :component_theme_color=>'0x001277', :carrier_select_color=>'0x7683FF', :label_text_color=>'0x000000',
                      :join_upper_gradient=>'0x6FAEFF', :join_lower_gradient=>'0x000000', :join_text_color=>'0xFFFFFF',
                      :cancel_link_color=>'0x001277', :border_color=>'0x888888', :carrier_text_color=>'0x000000', :public => true)

Theme.create(:id => 2, :name=>'Metallic', :background_color=>'0x000000', :title_text_color=>'0x7299FF',
                      :component_theme_color=>'0xDBF2FF', :carrier_select_color=>'0x000000', :label_text_color=>'0xDBF2FF',
                      :join_upper_gradient=>'0x2B25FF', :join_lower_gradient=>'0xBEFFAC', :join_text_color=>'0x000000',
                      :cancel_link_color=>'0xFF7C12', :border_color=>'0x000000', :carrier_text_color=>'0x000000', :public => true)

Theme.create(:id => 3, :name=>'Blues', :background_color=>'0x0060EC', :title_text_color=>'0x000374',
                      :component_theme_color=>'0x000374', :carrier_select_color=>'0x4357FF', :label_text_color=>'0x000000',
                      :join_upper_gradient=>'0x4357FF', :join_lower_gradient=>'0xffffff', :join_text_color=>'0x000000',
                      :cancel_link_color=>'0xffffff', :border_color=>'0x666666', :carrier_text_color=>'0x000000', :public => true)
puts "Success: Theme data loaded"

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

Установить ID не получается. Это означает, что если я решу добавить тему, назовем ее «Красная», тогда я просто хотел бы добавить оператор темы в этот файл фикстуры и вызвать задачу rake для повторного заполнения базы данных. Если я это сделаю, потому что темы принадлежат другим объектам и их идентификатор изменится при повторной инициализации, все ссылки будут разорваны.

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

Если да, то как я могу жестко закодировать идентификаторы и есть ли у этого недостатки?

Если нет, то как лучше всего заполнить базу данных?

Я буду искренне признателен за длинные и продуманные ответы, включающие лучшие практики.

Тони
источник

Ответы:

113

Обновление, поскольку эти ответы немного устарели (хотя некоторые все еще применимы).

Простая функция добавлена ​​в rails 2.3.4, db / seed.rb

Предоставляет новую задачу по рейку

rake db:seed

Подходит для заполнения общих статических записей, таких как состояния, страны и т. Д.

http://railscasts.com/episodes/179-seed-data

* Обратите внимание, что вы можете использовать фикстуры, если вы уже создали их, чтобы также заполнить задачу db: seed, поместив следующее в свой файл seed.rb (из эпизода railscast):

require 'active_record/fixtures'
Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "operating_systems")

Для Rails 3.x используйте ActiveRecord :: Fixtures вместо константы Fixtures.

require 'active_record/fixtures'
ActiveRecord::Fixtures.create_fixtures("#{Rails.root}/test/fixtures", "fixtures_file_name")
ajhit406
источник
28

Обычно требуются два типа исходных данных.

  • Основные данные, на которые может полагаться ядро ​​вашего приложения. Я называю это обычными семенами.
  • Данные об окружающей среде , например, для разработки приложения полезно иметь набор данных в известном состоянии, которые мы можем использовать для работы с приложением локально (ответ Factory Girl выше касается такого рода данных).

По моему опыту, я всегда сталкивался с необходимостью в этих двух типах данных. Итак, я собрал небольшой драгоценный камень, который расширяет семена Rails и позволяет вам добавлять несколько общих файлов семян в db / seed / и любые исходные данные окружающей среды в db / seed / ENV, например, db / seed / development.

Я обнаружил, что этого подхода достаточно, чтобы дать моим исходным данным некоторую структуру и дать мне возможность настроить мою среду разработки или промежуточную среду в известном состоянии, просто запустив:

rake db:setup

Крепления хрупкие и неудобные в обслуживании, как и обычные свалки sql.

james2m
источник
Мне нравятся термины «системные данные» и «данные времени выполнения» для описания вещей, которые код полагается на существующие и данные пользователей. Иногда грань между ними размыта.
Тим Абелл
27

factory_bot звучит так, как будто он сделает то, чего вы пытаетесь достичь. Вы можете определить все общие атрибуты в определении по умолчанию, а затем переопределить их во время создания. Вы также можете передать фабрике идентификатор:

Factory.define :theme do |t|
  t.background_color '0x000000'
  t.title_text_color '0x000000',
  t.component_theme_color '0x000000'
  t.carrier_select_color '0x000000'
  t.label_text_color '0x000000',
  t.join_upper_gradient '0x000000'
  t.join_lower_gradient '0x000000'
  t.join_text_color '0x000000',
  t.cancel_link_color '0x000000'
  t.border_color '0x000000'
  t.carrier_text_color '0x000000'
  t.public true
end

Factory(:theme, :id => 1, :name => "Lite", :background_color => '0xC7FFD5')
Factory(:theme, :id => 2, :name => "Metallic", :background_color => '0xC7FFD5')
Factory(:theme, :id => 3, :name => "Blues", :background_color => '0x0060EC')

При использовании с faker он может очень быстро заполнить базу данных ассоциациями без необходимости возиться с Fixtures (фу).

У меня есть такой код в грабельной задаче.

100.times do
    Factory(:company, :address => Factory(:address), :employees => [Factory(:employee)])
end
Ненавидит_
источник
11
FactoryGirl на самом деле предназначена для тестирования вместо приспособлений, но ее также можно использовать для загрузки материалов в производство. Используйте задачу rake, которая имеет db: migrate в качестве предварительного условия для загрузки всех данных по умолчанию. Возможно, вам потребуется сделать задачу сгребания достаточно интеллектуальной, чтобы она не создавала копии существующих данных.
Боб Аман,
2
Не рекомендуется использовать FactoryGirl для семян, проверьте этот пост .
blackbiron
26

Использование seeds.rbfile или FactoryBotотлично, но они, соответственно, отлично подходят для фиксированных структур данных и тестирования.

seedbankКамень может дать вам больше контроля и модульность для ваших семян. Он вставляет задачи с граблями, и вы также можете определять зависимости между вашими сидами. В ваш список задач по рейку будут добавлены следующие элементы (например):

rake db:seed                    # Load the seed data from db/seeds.rb, db/seeds/*.seeds.rb and db/seeds/ENVIRONMENT/*.seeds.rb. ENVIRONMENT is the current environment in Rails.env.
rake db:seed:bar                # Load the seed data from db/seeds/bar.seeds.rb
rake db:seed:common             # Load the seed data from db/seeds.rb and db/seeds/*.seeds.rb.
rake db:seed:development        # Load the seed data from db/seeds.rb, db/seeds/*.seeds.rb and db/seeds/development/*.seeds.rb.
rake db:seed:development:users  # Load the seed data from db/seeds/development/users.seeds.rb
rake db:seed:foo                # Load the seed data from db/seeds/foo.seeds.rb
rake db:seed:original           # Load the seed data from db/seeds.rb
Юрий
источник
1

В Rails есть встроенный способ заполнения данных, как описано здесь .

Другой способ - использовать драгоценный камень для более сложного или простого посева, например: seedbank .

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

Добавление актуального ответа, так как этот ответ был первым в Google.

SimonW
источник
-3

Лучше всего использовать приспособления.

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

p01nd3xt3r
источник
-4

Добавьте его в миграции базы данных, чтобы все получали его по мере обновления. Обрабатывайте всю свою логику в коде ruby ​​/ rails, поэтому вам никогда не придется связываться с явными настройками идентификатора.

Мэтт Рогиш
источник
если мне нужно изменить исходные данные, при использовании миграции все может стать беспорядочным. ваш второй комментарий действительно не имеет смысла. ссылки через внешние ключи будут уничтожены
Тони
c = Category.create (материал) p = Post.create (материал) p.category = c Нет необходимости явно устанавливать идентификаторы. Если вы измените исходные данные, вы просто создадите новую миграцию. Очень легко.
Мэтт Рогиш
это предполагает, что ассоциации могут быть созданы во время создания объекта. вот пример, когда я считаю, что ваша логика не работает ... поправьте меня, если я ошибаюсь. Я заполняю БД шаблонными темами. user id = 1 создает шаблон с id = 2 и с идентификатором темы = 4. в этот момент в базе данных находится следующая запись: template: id = 2, user_id = 1, theme_id = 4. теперь, если я повторно инициализирую базу данных, идентификатор темы = 4 теперь является идентификатором темы = 10 ... а затем шаблон пользователя неверно тематический
Тони
ну, это зависит от того, что вы подразумеваете под «повторной инициализацией» - если вы начнете с нуля, Rails обработает все ассоциации автоматически. Если вы жестко кодируете значения ID (плохо !!!), тогда да, это взорвется.
Мэтт Рогиш
хорошо, я начинаю понимать вашу точку зрения, но я должен запустить этот сценарий вами. Я заполняю базу данных таблицей поиска стран. США => id страны = 1. затем пользователь создает ресторан, который существует в США. в строке базы данных ресторанов указано country_id = 1. это очень часто, не так ли? Позже я решаю, что хочу добавить больше стран ... если я очищу базу данных и заново заполню таблицу поиска страны, теперь страна ресторанов больше не точна, если идентификатор не тот же. как мне с этим справиться?
Тони