Devise: Foreign key columns for roles in user_id - ruby-on-rails

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

Related

active_record-acts_as and devise integration

i'm writing my first rails application using active_record-acts_as and devise. I have an User (devise authentication and actable) , Client (act_as) and Owner (act_as).I overrided the registration_controller to add some extra fields in the devise form, fields like name, surname etc. that i need for Client and Owner. I'm trying to sign up both Client and Owner using the devise authentication of the User but adding other fields. I thought to define the authentication on the User to avoid duplicates in the schema. Is it possible to do this without define the devise controller of both Client and Owner?
client.rb
class Client < ActiveRecord::Base
acts_as :user
end
owner.rb
class Owner < ActiveRecord::Base
acts_as :user
end
user.rb
class Utente < ActiveRecord::Base
actable
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { registrations: 'registrations' }
resources :clients
resources :users
resources :owners
end
I think what you should understand about the gem you are using is that, it buys you the idea of having empty columns. However it is necessary you note that, each details goes to its respective table.
Having said that, you can use rails authentication on any table where you hope to set authentication on.
Now based on the later part of your question, where you asked to avoid duplicates on your table, you set validation in your model, such that any of your model becomes:
class Utente < ActiveRecord::Base
actable
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :email, :uniqueness => true
end
You could see documentation of how you set validations on active_record-acts_as here
Since its MTI with Devise, respective data goes to where it's suppose to be right out of the box, then I will suggest you set validations on other tables that acts_as :user, but on attributes that are not on the actable devise table. For example:
class Client < ActiveRecord::Base
acts_as :user
validates :school, :uniqueness => true
end

rails: devise ,cancan, rolify to get role name by user

I can easily to test if a user has certain role by
if user.has_role? :admin
How do I get a user's role name?
Something like
users = User.all
user.each{ |user|
puts user.role or users.role_name ?
}
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 :email, :password, :password_confirmation, :remember_me ,:username,:first_name,:last_name
# attr_accessible :title, :body
end
role model
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
attr_accessible :name,:id
scopify
end
you can use
user.roles.first.name

Changing Model associations after running migration

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.

How to set up custom validation before an association is created in Rails

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.

Mass assignment problem when instantiating a model

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

Resources