To start, I may be using the wrong callback for what I'm trying to do
and/or there may be a better "Rails Way" to accomplish this. If so, I'm all ears.
I've been referencing api.rubyonrails.org/v7.0.1/classes/ActiveRecord/Callbacks/ClassMethods
and
guides.rubyonrails.org/active_record_callbacks.html#creating-an-object
I need to implement:
"user sign up creates an account associated with user as owner"
(ultimately, user will belong_to account, and account will has_many users)
Accounts in database schema have name:string and owner_id:integer
Currently, I'm not able to access the newly created User, and the Account is not being created. I think I'm very close though.
current 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
outputs to the stacktrace:
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"=>"[email protected]", "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" = $1 LIMIT $2 [["email", "[email protected]"], ["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 ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id" [["email", "[email protected]"], ["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: "[email protected]", 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'
CodePudding user response:
As prasannaboga already wrote in his comment. Callbacks like these are running in the context of an instance. That means you do not need to call a specific user first because the current object is already that user.
Additionally, in the context of a model, the redirect_to call doesn't make any sense. Models don't know anything about requests and responses. redirect_to is a controller method and you need to add it to your controller.
The following callback method should work:
def create_account Account.create(owner_id: id, name: "#{name}'s Account") end
I wonder why you decided to not add an has_one :account or has_many :accounts association to your User model? By doing so you could simplify the method even more because then Rails would handle setting the id automatically, like this
build_account(name: "#{name}'s Account") # when `has_one` or
accounts.build(name: "#{name}'s Account") # when `has_many`
