Как добавить дополнительные данные в таблицу соединений на фабриках factory_bot - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть модели для пользователей и сайтов с has_many через связь между ними.В таблице присоединения sites_users есть одна дополнительная часть данных is_default, которая имеет тип boolean с намерением разрешить каждому пользователю иметь один сайт по умолчанию из списка связанных сайтов для этого пользователя.

модель пользователя

class User < ApplicationRecord
  has_many :sites_users
  has_many :sites, through: :sites_users
  accepts_nested_attributes_for :sites_users, allow_destroy: true
  ...
end

фабрика пользователя

factory :user do
  sequence(:email) { |n| "user_#{n}@example.com" }
  role { Role.find_by(title: 'Marketing') }
  image { Rack::Test::UploadedFile.new(Rails.root.join('spec', 'support', 'fixtures', 'user.jpg'), 'image/jpeg') }

  factory :super_admin do
    role { Role.find_by(title: "Super Admin") }
    admin true
  end

  before :create do |u|
    u.sites_users.build(site: site, is_default: true)
  end

конец

фабрика альтернативного пользователя Подход

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

factory :user do
  ...
  site { site }
  ...
end

Я был бы очень признателен за любую помощь, которую кто-либо мог оказать.Спасибо!

информация о схеме

таблица: пользователи

t.string "email", default: "", null: false
t.boolean "admin", default: false
t.integer "role_id"
t.string "first_name"
t.string "last_name"

таблица: сайты

t.string "domain", default: "", null: false
t.string "name", default: "", null: false
t.string "logo"
t.string "logo_mark"

таблица: sites_users

t.bigint "site_id", null: false
t.bigint "user_id", null: false
t.boolean "is_default", default: false

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Создайте фабрику для: site_user

factory :site_user, class: SiteUser do 
  site { site } # you could delete this line and add the site in factory :user
  is_default { false } # as specified in your DB
end

Вместо создания site на фабрике :user создайте ее отношение, используя приятный синтаксис:

factory :user do 
  ...
  sites_users { [FactoryBot.build(:site_user, is_default: true)] }
  ...
end

Itдолжен сделать трюк!

0 голосов
/ 25 октября 2018

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

В миграции:

add_foreign_key :users, :sites, column: :default_site_id

В классе пользователя:

class User < ApplicationRecord
  ...
  belongs_to :default_site, class_name: 'Site'
  ...

  # validate that the default site has an association to this user
  validate :default_site_id, inclusion: {in: sites.map(&:id)}, if: Proc.new {default_site_id.present?}
end

Это упростит ассоциацию и гарантирует, что ни у одного пользователя никогда не будет нескольких записей site_users, где is_default имеет значение true.Установка сайта по умолчанию на заводе должна быть тривиальной.

0 голосов
/ 24 октября 2018

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


Модель пользователя

class User < ApplicationRecord
  ...

  def set_site(site, default = false)
    SiteUser.find_or_create_by(
      user_id: id,
      site_id: site.id
    ).update_attribute(:is_default, default)
  end

end

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

Фабрика пользователей

factory :user do
  ...

  # to relate to new site with default true
  after(:create) do |u|
    u.set_site(create(:site), true)
  end

  # to relate to existing site with default true
  after(:create) do |u|
    u.set_site(site_name, true)
  end
end

Пожалуйста, дайте мне знать, если это поможет!(или если у кого-то есть более рейлический способ по умолчанию, который работает так же хорошо, я хотел бы услышать об этом!)

...