rails 关联:用户必须存在问题

rails associations: user must exists issue

我正在关注这个 tutorial 并且我正在开发一个应用程序,每个用户都有自己的植物列表。所以两个 tables:

最初 table PLANTS 没有一列来显示植物是由具有 id 的用户创建的。所以我添加了使用以下步骤:

所以现在架构如下所示:

ActiveRecord::Schema.define(version: 2021_04_27_111702) do
  #Table Plants
  create_table "plants", force: :cascade do |t|
    t.string "plant_name"
    t.float "temperature"
    t.float "humidity"
    t.float "water"
    t.string "light"
    t.string "soil"
    t.string "location"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "created_by"
    t.index ["created_by"], name: "index_plants_on_created_by"
  end

  #Table User Accounts
  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", precision: 6, null: false
    t.datetime "updated_at", precision: 6, 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
end

我在创建新工厂时更改了前端,以便它可以提交由用户 id 创建的 表单:

<%= form.number_field :created_by, id: :plant_created_by, class:"form-control", value: current_user.id, type: :hidden %>

仅供参考,这显示了尝试创建新 Plant 的用户的正确 ID,并且应用程序按预期工作,直到教程中的 2:42:00! (应该得到用户必须存在的错误,我这样做了)


现在是我出错的部分:

因为 created_by 是在之后创建的,所以我必须让我的 controllers/plants_controller.rb 知道它应该允许传递这个参数 (2:43:00)

  • def plant_params中添加新参数:
def plant_params
      params.require(:plant).permit(:plant_name, :temperature, :humidity, :water, :light, :soil, :location, :created_by)
end

但是当我尝试添加一个新工厂时,我仍然得到 User must exist on the front end,终端看起来像这样:

Started POST "/plants" for ::1 at 2021-04-27 15:34:18 +0300
Processing by PlantsController#create as HTML
  Parameters: {"authenticity_token"=>"[FILTERED]", "plant"=>{"plant_name"=>"oregano", "temperature"=>"50", "humidity"=>"20.5", "water"=
>"150", "light"=>"Partial Shade", "soil"=>"Any", "location"=>"Anywhere", "created_by"=>"3"}, "commit"=>"Create Plant"}
  Rendering layout layouts/application.html.erb
  Rendering plants/new.html.erb within layouts/application
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 3], ["LIMIT", 1]]
  ↳ app/views/plants/_form.html.erb:43
  Rendered plants/_form.html.erb (Duration: 5.7ms | Allocations: 1809)
  Rendered plants/new.html.erb within layouts/application (Duration: 6.6ms | Allocations: 1892)
[Webpacker] Everything's up-to-date. Nothing to do
  Rendered home/_header.html.erb (Duration: 0.2ms | Allocations: 123)
  Rendered layout layouts/application.html.erb (Duration: 64.9ms | Allocations: 6287)
Completed 422 Unprocessable Entity in 68ms (Views: 65.9ms | ActiveRecord: 0.2ms | Allocations: 8046)

我认为这里只是有些简单的混淆。

当您键入 belongs_to :user 时,rails 假定(按照惯例)table 有一个 user_id 列,并且这将用于关联 Plant -> User.

由于 rails 推断约定并且由于 plant.attributes['user_id'] #=> nil,当 rails 寻找“用户”时,它实际上是在查询

SELECT 
  "users".*
FROM 
  "users" 
WHERE 
  "users"."id" IS NULL

这显然不存在。

在您的情况下,您要关联的列称为 created_by。默认情况下 rails 无法知道这一点,但您可以将这种偏离惯例的情况告知协会。

class Plant < ApplicationRecord 
  belongs_to :user, foreign_key: 'created_by'
end

这里我们告诉 rails 关联称为 user 但我们想使用 created_by 列(属性)关联记录。

话虽这么说,但我认为 plant.user 读起来有点笨拙,相反,我们可以对上面的内容做一些小改动,使关联名称 creator

class Plant < ApplicationRecord 
  belongs_to :creator, foreign_key: 'created_by', class_name: 'User'
end

现在协会被称为 creator 但我们需要告诉 rails creator 属于 class User 以便它知道什么 table 连接到什么模型,当它 returns 对象时要实例化什么模型。

现在你有 plant.creator #=> <#User ...>,我认为这更自然。

需要对 has_many 关联进行其他类似修改。

文档: belongs_to has_many