如何在初始化另一个模型后正确地进行回调以创建模型?

How to properly make a callback to create a model, after initialize of another model?

首先,我可能对我正在尝试做的事情使用了错误的回调

and/or 可能有更好的“Rails 方式”来完成此任务。如果是这样,我洗耳恭听。

我一直在引用 api.rubyonrails.org/v7.0.1/classes/ActiveRecord/Callbacks/ClassMethods

guides.rubyonrails.org/active_record_callbacks.html#creating-an-object

我需要实施:

“用户注册创建一个与所有者关联的帐户”

(最终,用户将 belong_to 个帐户,帐户将 has_many 个用户)

数据库架构中的帐户有 name:string 和 owner_id:integer

目前,我无法访问新创建的用户,也没有创建帐户。我想我已经很接近了。

当前 models/user.rb:

class User < ApplicationRecord
  after_save :create_account
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable


  private

  def create_account
    Account.create(owner_id: user.id, name: "#{user.name}'s Account")
    redirect_to root_path
  end
end

输出到堆栈跟踪:

Started POST "/users" for ::1 at 2022-02-04 23:39:40 -0600
Processing by RegistrationsController#create as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"name"=>"tester", "phonenumber"=>"1234567890", "email"=>"test@test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
  TRANSACTION (0.2ms)  BEGIN
  User Exists? (1.1ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" =  LIMIT   [["email", "test@test.com"], ["LIMIT", 1]]
  User Create (0.6ms)  INSERT INTO "users" ("email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "created_at", "updated_at", "name", "phonenumber") VALUES (, , , , , , , , ) RETURNING "id"  [["email", "test@test.com"], ["encrypted_password", "[FILTERED]"], ["reset_password_token", "[FILTERED]"], ["reset_password_sent_at", "[FILTERED]"], ["remember_created_at", nil], ["created_at", "2022-02-05 05:39:40.493526"], ["updated_at", "2022-02-05 05:39:40.493526"], ["name", "tester"], ["phonenumber", "1234567890"]]
  TRANSACTION (0.2ms)  ROLLBACK
Completed 500 Internal Server Error in 298ms (ActiveRecord: 2.1ms | Allocations: 9928)



NameError (undefined local variable or method `user' for #<User id: nil, email: "test@test.com", created_at: "2022-02-05 05:39:40.493526000 +0000", updated_at: "2022-02-05 05:39:40.493526000 +0000", name: "tester", phonenumber: "1234567890">
Did you mean?  super):

app/models/user.rb:12:in `create_account'

正如 prasannaboga 已经在他的评论中写的那样。像这样的回调在实例上下文中是 运行。这意味着您不需要首先调用特定的 user,因为当前对象已经是该用户。

此外,在模型的上下文中,redirect_to 调用没有任何意义。模型对请求和响应一无所知。 redirect_to 是一个控制器方法,您需要将它添加到您的控制器中。

以下回调方法应该有效:

def create_account Account.create(owner_id: id, name: "#{name}'s Account") 结束

我想知道您为什么决定不向您的 User 模型添加 has_one :accounthas_many :accounts 关联?通过这样做,您可以进一步简化方法,因为 Rails 会自动处理 id 的设置,就像这样

build_account(name: "#{name}'s Account")  # when `has_one` or
accounts.build(name: "#{name}'s Account") # when `has_many`