I am having some unexpected behaviour with nested attributes in that the nested attributes are saving only the default values defined in the model. I have read a lot of documentation and tried many configurations of the build_ method prefixes in the controller, but this is the best I have come up with so far. Seem like the data is being persisted to the DB, however only the default values, so I suspect the issue lies with the form or the build method in controller. I thought the foreign keys were possibly wrong, although I think that's not the issue any more. Newish to rails (please forgive). I have read many questions and answers on related issues, but none have done the trick. Thanks for any tips and pointers.
I have 3 models, user, year and months. All belonging to each other in the following fashion:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :years, dependent: :destroy
end
class Year < ApplicationRecord
belongs_to :user
has_one :month, dependent: :destroy, inverse_of: :year
validates :year, presence: true
accepts_nested_attributes_for :month
end
class Month < ApplicationRecord
belongs_to :year, inverse_of: :month
attribute :january, :integer, default: 110
attribute :febuary, :integer, default: 0
....etc
end
The years controller is like this
def new
@year = current_user.years.build
end
def create
@year = current_user.years.build(year_params)
...etc...
end
def year_params
params.require(:year).permit(:year, :monthly_target, :user_id,
months_attributes: [:january, :febuary, :march, :april, :may, :june, :july, :august,
:september, :october, :november, :december])
end
The form is like this:
<div>
<%= form.label :year, style: "display: block" %>
<%= form.number_field :year, min:0, in: 1990...2051 %><span><small>add a year from 1990
to 2050</small></span>
</div>
<div>
<%= form.label :monthly_target, style: "display: block" %>
<%= form.number_field :monthly_target, min: 0, step: 25 %>
</div>
<%= form.fields_for :months do |month_form| %>
<div>
<%= month_form.label :january, style: "display: block" %>
<%= month_form.number_field :january, min: 0, step: 25%>
</div>
<div>
<%= month_form.label :febuary, style: "display: block" %>
<%= month_form.number_field :febuary, min: 0, step: 25 %>
</div>
Schema is like this:
ActiveRecord::Schema[7.0].define(version: 2022_09_20_123059) do
create_table "months", force: :cascade do |t|
t.integer "febuary"
t.integer "march"
t.integer "april"
t.integer "may"
t.integer "june"
t.integer "july"
t.integer "august"
t.integer "september"
t.integer "october"
t.integer "november"
t.integer "december"
t.integer "year_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["year_id"], name: "index_months_on_year_id"
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.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
create_table "years", force: :cascade do |t|
t.integer "year"
t.integer "monthly_target"
t.integer "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_years_on_user_id"
end
add_foreign_key "months", "years"
add_foreign_key "years", "users"
end
ps: this is rails 7 on windows, not using WSL2 (yet...!)
edit: here are params being sent through>>
{"authenticity_token"=>"[FILTERED]",
"year"=>
{"year"=>"2022",
"monthly_target"=>"25",
"months"=>{"january"=>"", "febuary"=>"", "march"=>"", "april"=>"",
"may"=>"", "june"=>"", "july"=>"", "august"=>"", "september"=>"",
"october"=>"", "november"=>"50", "december"=>""}},
"commit"=>"Create Year"}
also, here is the instance for the @year variable
>>
@year
=> #<Year id: nil, year: 2022, monthly_target: 25, user_id: 1,
created_at: nil, updated_at: nil>
you can see I added in the form 50 to november and the rest are empty fields. This is ok though as I opted for default values of 0 on all fields in the months model. I must say that I have found a decent work around, which I think is in the Rails ethos. I redesigned everything to just use one model "Year" and have added methods on the "Year" model to do the things I want, keeping the controller quite empty. This seems to work well, but I am slightly frustrated that I was unable to get the association between two models to work... Thanks for your help.