So I have a belongs_to relationship on a model (Idea, below) to a Period model which I've given the name, ':starting_period' within the Idea model. It works fine except when creating a new Idea, if I do not supply a Period, I get an ActiveModel error (see rails console below). It seems like it's ignoring the 'optional: true' parameter to belongs_to. Now I know I have a validation on starting_period but a) the condition on that validation will not fire on a new record and b) the error text shows that it isn't that one that's being fired off. What am I missing as this model will not have a starting period when first created?
Rails 6.0.4
Ruby 3.0.2
Rails Console:
irb(main):001:0> idea = Idea.new
=>
#<Idea:0x000055a412d45d30
irb(main):003:0> idea.title = 'test'
=> "test"
irb(main):004:0> idea.body = 'test'
=> "test"
irb(main):005:0> idea.user = User.all.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, email: "xxxxxxxxxxxxx", created_at: "2021-09-30 00:01:47.850876000 +0000", updated_at:...
irb(main):006:0> idea.save
=> false
irb(main):007:0> idea.errors
=>
#<ActiveModel::Errors:0x000055a412bde460
@base=
#<Idea:0x000055a412d45d30
id: nil,
title: "test",
created_at: nil,
updated_at: nil,
status: "draft",
votes_count: 0,
comments_count: 0,
progress: "review",
user_id: 1,
size: 0,
period_id: nil>,
@errors=[#<ActiveModel::Error attribute=starting_period, type=blank, options={:message=>:required}>]>
irb(main):008:0>
Models:
class Idea < ApplicationRecord
has_rich_text :body
#Relationships
has_one :action_text_rich_text, class_name: 'ActionText::RichText', as: :record #allows ransack to be able to use it
has_many :votes, dependent: :destroy
has_many :comments, dependent: :destroy
belongs_to :user
belongs_to :starting_period, optional: true, class_name: 'Period'
#validations
validates :title, presence: true
validates :body, presence: true
validates :user, presence: true
#yes, I know there's a validation here on that field BUT this is NOT
#the error that I'm getting and the condition is not being met upon
#new record creation. I can remove this line and still get the
#exact same problem and error message so this isn't the problem
validates :starting_period, presence: { message: "can't be blank if planned or started" }, if: :planned_or_started?
validates :size, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, presence: true
validates :size, numericality: { greater_than: 0, message: "can't be unsized if planned or started" }, if: :planned_or_started?
...
# upon creation, the progress will be "review" so it's not planned or started when creating it
def planned_or_started?
["planned", "in_progress", "complete"].include?(progress)
end
class Period < ApplicationRecord
#validations
validates :name, presence: true
validates :start_date, presence: true
validates :end_date, presence: true
validates :capacity, presence: true
validate :end_must_be_after_start
Migrations:
class AddStartPeriodToIdeas < ActiveRecord::Migration[6.1]
def change
add_reference :ideas, :period, on_delete: :nullify
end
end
Schema:
create_table "ideas", force: :cascade do |t|
t.string "title"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "status", default: 0, null: false
t.integer "votes_count", default: 0, null: false
t.integer "comments_count", default: 0, null: false
t.integer "progress", default: 0, null: false
t.integer "user_id", null: false
t.integer "size", default: 0, null: false
t.integer "period_id"
t.index ["period_id"], name: "index_ideas_on_period_id"
t.index ["user_id"], name: "index_ideas_on_user_id"
end
create_table "periods", force: :cascade do |t|
t.string "name"
t.date "start_date"
t.date "end_date"
t.integer "capacity"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
It helps if after you add optional: true to your belongs_to if you rebuild your docker container so that you're running the correct code.