class User
has_one :super_admin
end
class SuperAdmin
belongs_to :user
end
How would I create a SuperAdmin instance associating a certain user, from withing the User model?
I'm looking for something like this (in the User model), but it's not working:
def promote_to_super
self.super_admin.create!
end
You can use create_association(attributes = {}):
def promote_to_super
self.create_super_admin
end
See more here.
Related
I am brand new to the world of rails so please forgive my ignorance with this question :)
I am currently setting up a new app that has two models:
Account
User
My seed file looks like this:
account = Account.create!(name: 'Account Name')
account.users.create!(
first_name: 'Test',
last_name: 'Test',
email: 'test#test.com,
password: 'test',
owner: true
)
And the users model is:
class User < ApplicationRecord
belongs_to :account
...
end
I have created a custom Devise registrations controller to let new users sign up:
class Users::RegistrationsController < Devise::RegistrationsController
# GET /sign_up
def new
render inertia: 'Auth/Register', props: {}
end
# POST
def create # rubocop:disable Lint/UselessMethodDefinition
super
end
def sign_up_params
params.require(:user).permit( :email, :password, :first_name, :last_name)
end
end
BUT! I need to pre-create an account for a user before I actually create the user here and this is something I have been stuck on for a few days with no luck (to the point I've considered changing the association's).
The error is:
Account must exist
Which makes sense because we don't have an account when we create a new user which is what i need to do before the user is registered.
My best guess was I needed to do something like:
# POST
def create
account = Account.create!(name: 'Test')
account.users.create!(sign_up_params)
end
to mimic the logic of the seeds file but this seems distinctly wrong to me and doesn't work.
So my question is, is it possible and how can I pre-create an Account model for a user and then associate it to the user in the registrations create method before the user is persisted to the database?
In my final production code, the goal would be to create an Account type that will be created and associated with a user on registration but for now just getting a very basic MVC up and running is the goal :)
Thank you so much in advance for any help!
First off, I think the account is supposed to belong to the user, not the opposite.
The user model User.rb should look like this:
has_one :account
And the account model Account.rb should look like this:
belongs_to :user
And to create an account once the user is created, you can simply add this line to your user model:
after_create :create_account
and the account will be created automatically.
What about using?
user = User.new(sign_up_params)
user.build_account(name: 'Test')
user.save!
The problem is the line belongs_to :account in User model.
I would suggest you break your User model in two models
User
UserDetails
You can then add belongs_to :account in UserDetails model.
This will help in independent creation of users, will not be affected by account.
Something like below.
class User < ApplicationRecord
has_one :user_detail
...
end
class UserDetails < ApplicationRecord
belongs_to :user
belongs_to :account
...
end
class Account < ApplicationRecord
has_many :user_details
...
end
I have a User model that gets created through Devise, and after it's creation, I would like to automatically create a new Client (another model in my app). The new Client's atrribute, :user_id, should be equal to the :id of the User that was just created. I believe I need to use something like:
class Users::RegistrationsController < Devise::RegistrationsController
after_create :create_client
def create_client
Client.create(:user_id, :id) # Not sure what should go here
end
end
Is this the correct way to accomplish this? Also, if associations are important Client belongs_to :user and User has_one :client
You can add an after_create callback in User model(user.rb), check here for more information on how to create has_one associations.
class User < ActiveRecord::Base
after_save :add_client
def add_client
self.create_client(client_attribute1: value, client_attribute2: value)
end
end
Suppose I have a User model
user.rb
class User < ActiveRecord::Base
...
end
with attributes like: name, username, access
access is an enum that tells me if the user is "staff" or "customer"
To get the name and username of the logged in user, I can do:
current_user.name
current_user.username
And suppose I have a Staff model
staff.rb
class Staff < ActiveRecord::Base
belongs_to :user
end
with attributes like: salary, phone_number
And I also have a Customer model
customer.rb
class Customer < ActiveRecord::Base
belongs_to :user
end
with attributes like: address, phone_number
I want to be able to call this on my staff's controller:
current_user.staff.salary
And this on my customer's controller:
current_user.customer.address
WHAT I TRIED SO FAR
I overwrote sessions_controller.rb
def create
super
model_name = current_user.access.capitalize.constantize
spec = model_name.where(user_id: current_user.id).take
session[:spec] = spec
end
So I'm able to access it via session[:spec], but not via current_user. Any ideas?
Well to begin with, your User model should reference the staff or customer, even if they are to stay blank
class User
has_one :staff
has_one :address
Just by doing this, you should be able to use current_user.customer.address. However...
I suggest you add some convenient methods in ApplicationController or a module that you include
def staff_signed_in?
#staff_signed_in ||= (user_signed_in? and current_user.access == :staff)
end
def current_staff
#current_staff ||= (current_user.staff if staff_logged_in?)
end
# same for customer
# Note that I use instance variables so any database queries are executed only once !
Then you can simply call
<% if customer_signed_in? %>
<h2>Logged in as customer</h2>
<p>Address : <%= current_customer.address %>
<% end %>
EDIT : about your concerns concerning database hits
You gave the example of current_user.customer.cart.products
This is indeed quite a nested association. My suggestion above already reduces it by one level (ie current_customer == current_user.customer). Then you have to go through carts to reach products... it isn't so bad in my opinion.
If you need to call that often (current_customercustomer.cart) you can override the current_customer for a given controller and eager load the resources you know you will use use.
def UserShopController < ApplicationController
# Let's assume current_customer is defined in ApplicationController like I showed above
# UserShopController always uses the customer cart, so let's load it right at the beginning
...
private
# Override with eager loading
def current_customer
#current_customer ||= (current_user.customer.includes(:cart) if customer_logged_in?)
end
add has_one :customer to your user.rb
Your user model should be like below to accessing related model.
class User < ActiveRecord::Base
has_one :customer
end
If I have a user that has_many user_logins and a user_logins that belongs to user - When a user_login is created I'm using UserLogin.create(userlogin_params) and then my strong params permits the user_id column - but this alone is not saving the current users I.D to the column as it is coming out as nil.
How do I make it save the I.D?
User model:
has_many :user_logins
UserLogin model
belongs_to :user
accepts_nested_attributes_for :user
UserLoginController:
...
def create
#user_login = UserLogin.new(user_login_params)
...
end
...
def user_login_params
param.require(:user_login).permit(
:user_login_attribute1,
:user_login_attribute2,
user_attributes: [
:id,
:user_attribute1,
:user_attribute2
]
)
end
Tell me if it helps.
There are 2 issues here at hand.
First: How do you create an association with the parent record automagically there?
Second: How do you do this so your controller action isn't a giant hole waiting for a hacker to stick their nose in.
You need to start from the parent, then build the child, not start with the child and build the parent.
Consider the following:
class User < ActiveRecord::Base
has_many :logins, class_name: "UserLogin"
end
class UserLogin < ActiveRecord::Base
belongs_to :user
end
class UserLoginsController < ApplicationController
def create
if new_user_login(user_login_params).save
redirect_to :wherever
else
render :new
end
end
private
def new_user_login(attrs={})
current_user.logins.create(attrs)
end
def user_login_params
param.require(:user_login).permit(:attr_1, :attr_1)
end
Do not pass IDs into any secure params hash unless that ID is selectable by the user. If you allow an ID into secure params, a hacker can start moving records around to other objects and destroy your database integrity.
If you would like pairing help on this problem live and in person, you can check out my codementor profile at https://codementor.io/rubycasts/#reviews
We have a Role model that is connected to User via role_id, and there are some users that don't have roles assigned.
Would like to set a default Role on selecting users when they don't explicitly have a role set. Didn't setup a default in the migration.
Trying to use a loop:
users.each do |user|
# some users don't have roles so there are errors
end
The Role model:
class Role < ActiveRecord::Base
has_many :users
# Can I add something to set the default role
end
The user model:
class User < ActiveRecord::Base
belongs_to :role
end
Also if this is not a railsy way to approach this problem, any suggestions would be appreciated.
You could add an initialize method to the User model
after_initialize :init
def init
self.role =>'my_default_role'
end
You could also do a simple check for user.role_id before you do something role-related in your loop.
users.each do |user|
user.role = Role.find_by(name: 'user') unless user.role
end
Alternatively, you could modify the role method in your user class to add a default one if it's undefined.
class User < ActiveRecord::Base
belongs_to :role
def role
return :role if :role
Role.find_by(name: 'user')
end
end
Finally, you could just create a migration to add a role to all users who don't have one.