I have a problem with FactoryBot for creating Image from Image model which has a polymorphic association throw 'parent' and when I want to create an instance from Image by FactoryBot but get this error in CLI:
(ActiveModel::MissingAttributeError: can't write unknown attribute parent_id
)
I use RSpec for testing and I want to test Image model
user.rb (user model has_one avatar for Image)
class User < ApplicationRecord
include Generals::SoftDelete
include Methods::User
include Scopes::User
include Validations::User
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :created_coffee_shop, class_name: 'CoffeeShop', foreign_key: 'creator_id'
has_many :maintained_coffee_shop, class_name: 'CoffeeShop', foreign_key: 'maintainer_id'
has_many :owened_coffee_shop, class_name: 'CoffeeShop', foreign_key: 'owner_id', dependent: :destroy
has_many :enrolments
has_many :enroled_tables, through: :enrolments, source: :table
has_one :avatar, as: :parent, class_name: 'Image', dependent: :destroy
#JWT config
before_create :add_jti
def add_jti
self.jti ||= SecureRandom.uuid
end
#role config
enum role: [:sys_master, :sys_admin, :sys_expert, :coffee_owner,:player]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :player
end
#soft delete config for davise
def active_for_authentication?
raise ErrorHandling::Errors::User::DeletedUser.new(deleted_at: deleted_at) if deleted_at?
return true
end
end
image.rb (provide a polymorphic assocccation as parent)
class Image < ApplicationRecord
include Methods::Image
include Scopes::Image
include Validations::Image
belongs_to :parent, polymorphic: true
mount_uploader :image, AvatarUploader
end
image_spec.rb (testing image factory)
require 'rails_helper'
RSpec.describe Image, type: :model do
describe "#validations" do
it "should have a valid factory" do
user = create(:player)
image = build(:picture, parent: user, image: nil)
expect(image).to be_valid
end
end
end
images.rb (Image Factory)
FactoryBot.define do
factory :picture, class: Image do
image { Rack::Test::UploadedFile.new(Rails.root.join('spec/support/defultAvatar.jpg')) }
parent {|a| a.association(:player)}
end
end
users.rb (user factory)
require 'faker'
FactoryBot.define do
# :sys_master, :sys_admin, :sys_expert, :coffee_owner,:player
factory :player, class: ApiUser do
sequence(:email) { |n| "test#{n}#{rand(100000..999999).to_s}@player.com" }
password { "123456" }
role {"player"}
jti {Faker::Alphanumeric.alphanumeric(number: 20)}
end
factory :coffee_owner, class: ApiUser do
sequence(:email) { |n| "test#{n}#{rand(100000..999999).to_s}@coffee_owner.com" }
password { "123456" }
role {"coffee_owner"}
jti {Faker::Alphanumeric.alphanumeric(number: 20)}
end
factory :sys_expert, class: ApiUser do
sequence(:email) { |n| "test#{n}#{rand(100000..999999).to_s}@sys_expert.com" }
password { "123456" }
role {"sys_expert"}
jti {Faker::Alphanumeric.alphanumeric(number: 20)}
end
factory :sys_admin, class: ApiUser do
sequence(:email) { |n| "test#{n}#{rand(100000..999999).to_s}@sys_admin.com" }
password { "123456" }
role {"sys_admin"}
jti {Faker::Alphanumeric.alphanumeric(number: 20)}
end
factory :sys_master, class: ApiUser do
sequence(:email) { |n| "test#{n}#{rand(100000..999999).to_s}@sys_master.com" }
password { "123456" }
role {"sys_master"}
jti {Faker::Alphanumeric.alphanumeric(number: 20)}
end
end
schema.rb
ActiveRecord::Schema.define(version: 2019_12_09_070629) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "board_games", force: :cascade do |t|
t.string "name", null: false
t.string "publisher", null: false
t.integer "min_player", null: false
t.integer "max_player", null: false
t.integer "play_time", null: false
t.text "description"
t.datetime "deleted_at"
t.bigint "coffee_shop_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["coffee_shop_id"], name: "index_board_games_on_coffee_shop_id"
t.index ["name", "coffee_shop_id"], name: "index_board_games_on_name_and_coffee_shop_id", unique: true
end
create_table "coffee_shops", force: :cascade do |t|
t.string "name", null: false
t.string "address", null: false
t.bigint "owner_id", null: false
t.bigint "creator_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.bigint "maintainer_id", null: false
t.index ["creator_id"], name: "index_coffee_shops_on_creator_id"
t.index ["maintainer_id"], name: "index_coffee_shops_on_maintainer_id"
t.index ["owner_id"], name: "index_coffee_shops_on_owner_id"
end
create_table "enrolments", force: :cascade do |t|
t.bigint "user_id"
t.bigint "table_id"
t.datetime "deleted_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["table_id"], name: "index_enrolments_on_table_id"
t.index ["user_id", "table_id", "deleted_at"], name: "index_enrolments_on_user_id_and_table_id_and_deleted_at", unique: true
t.index ["user_id"], name: "index_enrolments_on_user_id"
end
create_table "events", force: :cascade do |t|
t.string "name", null: false
t.string "description", null: false
t.datetime "deleted_at"
t.bigint "coffee_shop_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "opens_at", null: false
t.datetime "enrol_start_time", null: false
t.datetime "enrol_end_time", null: false
t.datetime "event_start_time", null: false
t.datetime "event_end_time", null: false
t.datetime "closed_at", null: false
t.index ["coffee_shop_id"], name: "index_events_on_coffee_shop_id"
end
create_table "images", force: :cascade do |t|
t.string "image"
t.string "parent_type"
t.bigint "parent_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["parent_type", "parent_id"], name: "index_images_on_parent_type_and_parent_id"
end
create_table "tables", force: :cascade do |t|
t.string "table_code", null: false
t.datetime "deleted_at"
t.bigint "event_id"
t.bigint "board_game_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "capacity"
t.integer "enroled", default: 0
t.index ["board_game_id"], name: "index_tables_on_board_game_id"
t.index ["event_id"], name: "index_tables_on_event_id"
t.index ["table_code", "event_id"], name: "index_tables_on_table_code_and_event_id", unique: true
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "jti", null: false
t.integer "role"
t.datetime "deleted_at"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["jti"], name: "index_users_on_jti", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "board_games", "coffee_shops"
add_foreign_key "coffee_shops", "users", column: "creator_id"
add_foreign_key "coffee_shops", "users", column: "maintainer_id"
add_foreign_key "coffee_shops", "users", column: "owner_id"
add_foreign_key "enrolments", "tables"
add_foreign_key "enrolments", "users"
add_foreign_key "events", "coffee_shops"
add_foreign_key "tables", "board_games"
add_foreign_key "tables", "events"
end
I would try the following in your image factory: association :parent, factory: :player
.
FactoryBot.define do
factory :picture, class: Image do
image { Rack::Test::UploadedFile.new(Rails.root.join('spec/support/defultAvatar.jpg')) }
association :parent, factory: :player
end
end