1

我还是 Ruby / Rails 的新手,在运行命令之前我需要你的帮助以确保我的种子是好的rails db:seed

这是我的种子:

require 'faker'

puts "Creating 10 fake user heros..."
10.times do
  user = User.create!(
    username: Faker::DcComics.hero,
    password: "123456",
    email: "#{user.username}@gmail.com",
    bio: "Hi, I'm #{user.username}. Faker::Movie.quote",
    avatar: Faker::LoremFlickr.image(size: "900x900", search_terms: ['dccomics'])
  )
  puts "#{user.username} created!"
end

puts "Creating 10 fake hero services..."
10.times do
  service = Service.create!(
    name: "#{Faker::Verb.ing_form} service",
    description: "I'll use my #{Faker::Superhero.power} to accomplish the mission",
    address: "#{Faker::Address.street_address}, #{Faker::Address.city}",
    photos: Faker::LoremFlickr.image(size: "900x900", search_terms: ["#{Faker::Verb.ing_form}"]),
    user_id: rand(user.id)
  )
  puts "#{service.name} created!"
end

puts "Finished!"

我想我会有几个问题,尤其是:

  • 我的插值:我不确定我是否可以将它与 Faker 一起使用
  • 我想使用username和中给出的相同用户名email,我做得对吗?
  • 我的用户模型在数据库表中没有头像,但是has_one_attached :avatar我可以给它一个种子吗?
  • 关于我的服务模型的相关问题 ( has_many_attached :photos)。我怎样才能为它生成几张图片?
  • 我想user_id从上面创建的其中一个随机给我的服务模型,我真的不知道我该如何继续......
4

2 回答 2

3

我的插值:我不确定我是否可以将它与 Faker 一起使用

插值适用于任何表达式。甚至是多个陈述。"#{ a = 1 + 1; b = 2 + 2; a + b}"会产生"6". 但不要那样做,这很混乱。

name: "#{Faker::Verb.ing_form} service",

相当于

name: Faker::Verb.ing_form.to_s + " service"

在一些地方你错过了插值。

bio = "Hi, I'm #{user.username}. Faker::Movie.quote"

那应该是...

bio = "Hi, I'm #{user.username}. #{Faker::Movie.quote}"

在其他地方,插值是不必要的。

search_terms: ["#{Faker::Verb.ing_form}"]

Faker::Verb.ing_form已经返回一个字符串,不需要插值。

search_terms: [Faker::Verb.ing_form]

我想使用用户名和电子邮件中给出的相同用户名,我做得对吗?

user不,在创建之前您不能引用。如果你尝试,你会得到类似的东西undefined method `username' for nil:NilClassusernil并且nil没有一个名为username.

相反,您可以创建一个用户,设置其电子邮件,然后保存。

user = User.new(
  username: Faker::DcComics.hero,
  password: "123456",
  avatar: Faker::LoremFlickr.image(size: "900x900", search_terms: ['dccomics'])
)
user.email = "#{user.username}@gmail.com"
user.bio = "Hi, I'm #{user.username}. #{Faker::Movie.quote}"
user.save!

或者您可以先创建用户名并将其存储在变量中以供参考。

  username = Faker::DcComics.hero
  user = User.create!(
    username: username,
    password: "123456",
    email: "#{username}@gmail.com",
    bio: "Hi, I'm #{username}. #{Faker::Movie.quote}",
    avatar: Faker::LoremFlickr.image(size: "900x900", search_terms: ['dccomics'])
  )

我的用户模型在 DB 表中没有头像,但是 has_one_attached :avatar,我可以给它一个种子吗?

我对Rails 中的附件不是很熟悉,但我认为它应该像你写的那样工作。


我想从上面创建的其中一个中为我的服务模型提供一个随机 user_id,我真的不知道我该如何继续......

简单的事情就是使用sample.

user = User.all.sample

pluck我们可以使用仅获取 ID 来改善这一点。

user = User.pluck(:id).sample

但是,这会加载所有用户。对于小型测试数据库来说,这不是问题。对于生产代码,这是一种巨大的浪费。相反,我们可以使用order by random() limit 1. 在 Rails 6 中它有点笨重。

User.order(Arel.sql('RANDOM()')).pluck(:id).first

请参阅此答案以获取解释。

请注意,如果您已经加载了用户,请传递用户,而不是其 ID。这避免了服务必须再次加载用户。

10.times do
  user = User.order(Arel.sql('RANDOM()')).pluck(:id).first
  service = Service.create!(
    ...
    user: user
  )
end

但是有更好的方法...


关于我的服务模型的相关问题(has_many_attached :photos)。我怎样才能为它生成几张图片?

在这里,我们实现了真正的飞跃。不要生成静态测试数据,而是使用工厂。FactoryBot可以轻松定义“工厂”以使用 Faker 生成测试数据。你已经成功了一半。FactoryBotRails让FactoryBot了解如何使用 Rails 模型。

用户工厂看起来像这样。

FactoryBot.define do
  factory :user do
    username { Faker::DcComics.hero }
    password { "123456" }
    email { "#{username}@gmail.com" }
    bio { "Hi, I'm #{username}. #{Faker::Movie.quote}" }
    avatar { Faker::LoremFlickr.image(size: "900x900", search_terms: ['dccomics']) }
  end
end

请注意,我们可以基于email. username属性可以引用其他属性。那是因为属性实际上是有点像这样的小函数:

class UserFactory do
  def username
    @username ||= Faker::DDcComics.hero
  end

  def email
    @email ||= "#{username}@gmail.com"
  end
end

并制作10个...

users = FactoryBot.create_list(:user, 10)

您可以覆盖默认值。如果您想要具有特定电子邮件地址的用户...

user = FactoryBot.create(:user, email: "c.kent@dailyplanet.com")

由于您可以即时创建用户,因此您不再需要播种特定数据。

现在服务。让我们看一下Service工厂。为了提供服务,我们需要照片。

  factory :service do
    name { "#{Faker::Verb.ing_form} service" }
    description { "I'll use my #{Faker::Superhero.power} to accomplish the mission" }
    address { "#{Faker::Address.street_address}, #{Faker::Address.city}" }
    user
    # photos is presumably has-many_attached and so takes an Array.
    photos {
      [
       Faker::LoremFlickr.image(
         size: "900x900",
         search_terms: [Faker::Verb.ing_form]
       )
      ]
    }
  end

看看user。FactoryBot 将自动填写使用您的用户工厂创建的用户。解决了使用随机用户创建服务的问题。

我们的最后一步是通过定义一个来制作照片来干燥我们的工厂。

factory :photo, class: Faker::LoremFlickr do
  size { "900x900" }
  search_terms { Faker::Lorem.words }

  initialize_with do
    Faker::LoremFlickr.image(attributes)
  end
end

这不是 Rails 模型,因此我们需要通过向 FactoryBot 提供其类以及如何对其进行初始化来教 FactoryBot 如何制作照片。attributes是一个包含 size 和 search_terms 的 Hash。

另请注意,我使用了更通用的搜索词。需要特定搜索词的工厂将提供自己的搜索词。

我们可以制作任意数量的照片。

photos = FactoryBot.build_list(:photos, 3)

使用照片工厂,我们可以干掉用户和服务工厂。在这里,一切都在一起。

FactoryBot.define do
  factory :photo, class: Faker::LoremFlickr do
    size { "900x900" }
    search_terms { Faker::Lorem.words }

    initialize_with do
      Faker::LoremFlickr.image(attributes)
    end
  end

  factory :user do
    username { Faker::DcComics.hero }
    password { "123456" }
    email { "#{username}@gmail.com" }
    bio { "Hi, I'm #{username}. #{Faker::Movie.quote}" }
    avatar { build(:photo, search_terms: ['dccomics']) }
  end

  factory :service do
    name { "#{Faker::Verb.ing_form} service" }
    description { "I'll use my #{Faker::Superhero.power} to accomplish the mission" }
    address { "#{Faker::Address.street_address}, #{Faker::Address.city}" }
    user
    photos {
      build_list(:photo, 3, search_terms: [Faker::Verb.ing_form])
    }
  end
end

现在,当您需要一项服务进行测试时,您可以要求提供一项服务。

service = FactoryBot.create(:service)

想要使用不同名称的服务?

service = FactoryBot.create(:service, name: "Universal Exports")

没有照片怎么办?

service = FactoryBot.create(:service, photos: [])

这只是触及 FactoryBot 功能的皮毛。

工厂远比种子文件灵活方便。

于 2020-11-17T22:56:03.143 回答
0

aborted消息中必须有一个种子失败的特定行。可能,它可以是email. 如果用户名是:“小丑”怎么办?电子邮件不能是“The Joker@gmail.com@”。

尝试这个:

require 'faker'

puts "Creating 10 fake user heros..."
10.times do
  user = User.create!(
    username: Faker::DcComics.hero,
    password: "123456",
    email: "#{username..gsub(/\s+/, "").downcase}@gmail.com",
    bio: "Hi, I'm #{user.username}. #{Faker::Movie.quote}"
  )
  puts "#{user.username} created!"
end

于 2020-11-17T22:35:20.107 回答