I have a User model (Devise) and have created a Profile model with has_one / belongs_to relationship. I'm trying to automatically create a profile when the User is created as follows :
class User < ActiveRecord::Base
has_many :videos, :dependent => :destroy
has_one :profile, :dependent => :destroy
after_create :create_profile
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
protected
def create_profile
Profile.create :user_id => self.id
end
end
The profile gets created but the user id does not get populated. I get a Mass Assignment warning with regard to setting :user_id on the profile because I have attr_accessible exposing a few fields on the Profile.
I dont want to remove the attr_accessible but dont understand why setting one field is considered mass assignment. I figured this might be to do with passing a hash so Ive tried the following as a workaround :
#profile = Profile.create
#profile.user_id = self.id
This removes the warning but the user_id is still not getting set on the profile. What is the correct way to go about solving this ?
Any clarity much appreciated ! :)
Are you calling #profile.save at the end of your workaround?
Maybe you can try this:
def create_profile
self.build_profile.save
end
Related
I have three models as follows:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role, polymorphic: true
validates_presence_of :first_name, :last_name, :email, :password,
:password_confirmation
end
student.rb
class Student < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy
accepts_nested_attributes_for :user
end
teacher.rb
class Teacher < ActiveRecord::Base
has_one :user, as: :role, dependent: :destroy
accepts_nested_attributes_for :user
end
I have user registration and login working as expected. However, I cannot figure out how to direct users to the appropriate homepage when they're logged in.
I handle routing for authenticated users as follows:
authenticated :user do
root to: "students#home", as: :user_root
end
Ideally if current user's role attribute is a student, then it sets students#home as :user_root. If it's a teacher, then it sets teachers#home as :user_root. Is there any way to handle this purely in routes?
They way you've structured it seems confusing to me. How much do teachers and students really have in common? Won't students and teachers need different associations, fields, and everything?
Why not have completely separate Student and Teacher models with different devise scopes? See devise wiki configuring multiple models: https://github.com/plataformatec/devise#configuring-multiple-models
For shared functionality you can have both inherit from an abstract model or use concerns / modules for shared functionality.
module DeviseConcern
extend ActiveSupport::Concern
included do
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :first_name, :last_name, :email, :password,
:password_confirmation
end
end
While playing around with AJcodez's solution, some things like user authentication were less than pleasant to implement. I ended up opting for my original implementation.
One lesser known things about routes is that they can have lambas in them. Our routes ended up looking like the following:
authenticated :user, lambda { |u| u.role_type == "Student" } do
root to: "students#home", as: :student_root
end
authenticated :user, lambda { |u| u.role_type == "Teacher" } do
root to: "teachers#home", as: :teacher_root
end
I used rails composer to create a starter app for my rails project. It is using devise to create and manage roles
I have following roles for my User: Recruiter, Applicant
A User can one or both of [Recruiter, Applicant]
I looked at the User model , but it doesnt have any foreign key role_id column. I added that column myself,and I am facing following issues
1] The app only assigns role_id=1 for every user I sign up
2] For user who is both a recruiter and an applicant, would there be 2 roles in User column with different Ids [1 and 2] , how would/should this model be handled.
This is my User model:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :admin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :user_id, :role_ids
validates_presence_of :email
has_many :applications
has_many :jobs
end
How do you use User(devise which store email and password) to belong_to Profile and Profile has_one User? When I looked up the database profile_int is still nil hmmm... not sure where did I do wrong?
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_id
# attr_accessible :title, :body
belongs_to :profile
end
class Profile < ActiveRecord::Base
attr_accessible :dob, :firstName, :lastName, :school_id, :schYear, :user_attributes
belongs_to :school
has_one :user
accepts_nested_attributes_for :user
end
I know usually I should do something like this Profile.create(.......) but I am not sure where to do this if I am doing it with a devise
Should :schoolstrong text be ':schoolstrong_text'? Did you run rake db:migrate ?
Also, checking your schema could be helpful too.
A common practice in associating a Devise User with a Profile model is making the profile the child of the user:
# app/models/user.rb
class User < ActiveRecord::Base
has_one :profile
end
# app/models/profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
end
Then, within your User model, you'd create an after_create hook to create a new Profile model and associate it with the newly created user:
# app/models/user.rb
after_create :create_profile
def create_profile
profile = Profile.create
self.profile = profile
self.save
end
I have a Devise User model with the following contents for which I did run migration.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :token_authenticatable, :confirmable, :lockable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :role
# attr_accessible :title, :body
ROLES = ['admin', 'network/system admin', 'manager', 'programmer']
def role?(base_role)
ROLES.index(base_role.to_s) <= ROLES.index(role)
end
end
later on , I added the below two lines to the same model and run migration for Ticket, Projects and Assignments.
has_many :projects, :through => :assignments
has_many :tickets
Does the above update the association of user with the Tickets and Projects? Is there any problem in changing associations in model after running migration for the same? I want to know it as I am developing a Rails app now.
Thanks :)-
You should also have association...
has_many :assignments
in your user model.
no other updation is required.
Not sure if the question makes sense so I'll describe through an example:
Basically I have a company model in my app and a company employee. The employee is a devise model and can sign up/sign in. I have a wizard set up for the employee to select the company they work for after signing up, so the model accepts nested attributes for company.
During the stage where they select the company they work for, I want to set up a validation to ensure they only select the company they work for by matching the employee's email domain with the company's email domain in my db. At which point should i do this? Should I set up a custom validator or use a callback?
Here's my code:
Employee:
class Employee < ActiveRecord::Base
##################
# Base
###################
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :company_id, :company_attributes
##################
# Associations
###################
belongs_to :company
accepts_nested_attributes_for :company
has_many :authentications, dependent: :destroy
end
Company:
class Company < ActiveRecord::Base
##################
# Base
###################
attr_accessible :name, :address_attributes, :email, :phone_number, :website, :confirmed
##################
# Associations
###################
has_one :address
accepts_nested_attributes_for :address
has_many :employees
end
And here is the controller which is responsible for employees selecting a company, it's a wicked gem wizard controller.
class EmployeeStepsController < ApplicationController
before_filter :authenticate_employee!
include Wicked::Wizard
steps :personal, :company_details, :enter_company_details
def show
#employee = current_employee
case step
when :enter_company_details
if #employee.company
skip_step
else
#employee.build_company.build_address
end
end
render_wizard
end
def update
#employee = current_employee
#employee.attributes = params[:employee]
render_wizard #employee
end
private
def finish_wizard_path
employee_url(#employee)
end
end
I have another controller which deals with adding companies into the site separately for site admins but I only want to trigger the email validation in the wizard controller aka when employees are selecting their company. Any advice on this?
class Employee < ActiveRecord::Base
##################
# Base
###################
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :company_id, :company_attributes
##################
# Associations
###################
belongs_to :company
accepts_nested_attributes_for :company
has_many :authentications, dependent: :destroy
# HERE
validate :my_custom_vaildator
private
def my_custom_vaildator
# do stuff .....
# based off that stuff add errors
if some_logic_about_your_company?
self.errors.add(:base, "select the company you work for.")
elsif some_other_logic?
self.errors.add(:name, "your name sucks.")
end
end
end
REMEMBER:
never return nil or false. If you do it will go BANG!
=)
all this said the front end should never allow them to select something that isn't allowed.