嵌套属性未关联

Nested attributes not being associated

提问人:Niko 提问时间:9/21/2022 最后编辑:Niko 更新时间:9/22/2022 访问量:33

问:

我在嵌套属性方面遇到了一些意想不到的行为,因为嵌套属性仅保存模型中定义的默认值。我阅读了很多文档,并尝试了控制器中build_方法前缀的许多配置,但这是我迄今为止想出的最好的。似乎数据被持久化到数据库中,但只有默认值,所以我怀疑问题出在控制器中的表单或构建方法上。 我认为外键可能是错误的,尽管我认为这不再是问题了。 新铁轨(请原谅)。我读过很多关于相关问题的问题和答案,但没有一个能解决问题。感谢您的任何提示和指示。

我有 3 个模型,用户、年份和月份。所有都以下列方式相互归属:

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

岁月控制器是这样的

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

形式如下:

  <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>

架构如下:

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:这是 Windows 上的 Rails 7,未使用 WSL2(尚未...!

编辑:这是正在发送的参数>>

{"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"}

此外,这里是@year变量的实例

>> 

@year

=> #<Year id: nil, year: 2022, monthly_target: 25, user_id: 1, 
created_at: nil, updated_at: nil>

你可以看到我在表格 50 中添加了 11 月,其余的都是空字段。不过这没关系,因为我在月份模型中的所有字段上都选择了默认值 0。 我必须说,我找到了一份体面的工作,我认为这符合 Rails 的精神。我重新设计了所有内容,只使用一个模型“Year”,并在“Year”模型上添加了方法来做我想做的事情,使控制器保持相当空。这似乎效果很好,但我有点沮丧,因为我无法让两个模型之间的关联起作用......感谢您的帮助。

Ruby-on-Rails 嵌套 属性

评论

0赞 Haumer 9/22/2022
你能发布参数中传递的内容吗?这样,我们就可以看到从表单中拉出的内容,并检查生成的对象是否有效。您可以通过在创建操作(或使用 Pry 等其他工具)中敲打“加注”来实现这一点。
0赞 Niko 9/22/2022
@Haumer,非常感谢您的帮助。我已经发布了一个带有可见参数的编辑。我应该说,我研究了一种不同的方法,它只使用一个模型,并在其中声明了额外的方法来做我想做的事情。这效果很好,尽管我不得不接受我无法使用嵌套属性方法。也许我误解了它们的用例。

答: 暂无答案