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

Posted

技术标签:

【中文标题】rails 关联:用户必须存在问题【英文标题】:rails associations: user must exists issue 【发布时间】:2021-07-20 19:16:56 【问题描述】:

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

表 A:植物:植物名称:字符串,温度:浮动,湿度:浮动,... 表 B:设计用户:默认参数来自 devise。

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

models/plant.rb 我添加了以下内容:belongs_to :usermodels/user.rb 我添加了以下has_many :plantsGitBash 中:rails g migration add_created_by_to_plants created_by:integer:index 然后在 GitBash 中推送迁移:rails db:migrate

所以现在架构看起来像这样:

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

仅供参考,这显示了尝试创建新工厂的用户的正确 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 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)

【问题讨论】:

【参考方案1】:

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

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

由于 Rails 推断约定,并且因为 plant.attributes['user_id'] #=&gt; 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 属于User 类,以便它知道要加入哪个表以及在返回对象时要实例化哪个模型。

现在你有了plant.creator #=&gt; &lt;#User ...&gt;,我认为这是一个更自然的阅读方式。

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

文档: belongs_to has_many

【讨论】:

以上是关于rails 关联:用户必须存在问题的主要内容,如果未能解决你的问题,请参考以下文章

Rails 关联不存在。更好的方法?

Rails 3:通过关联项验证是不是存在至少一个有多个

Rails复杂模型关联,用户和团队之间的共享文档

Rails - has_one 关系:关联和非关联对象的范围

用户必须存在于Rails 5中

通过 has_many 的 Rails 4 应用程序