Rails relationship for a single user role - ruby-on-rails

i'm currently working on building a site like freelancer using RoR, but i'm stuck somewhere, my user table which was generated with devise has a role column which can be admin, client or freelancer. Also i have a skills table which belongs to user but i don't want every user to have skills except from the users with the role of freelancer, how do i go about this, i'm currently using cancancan for user authorization and devise for authentication, is roles the best solution to this or STI and how would you advice me to approach this problem, here's an example code
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :user_roles
has_many :skills
has_many :skills, through: :user_skills ## I don't want all users to have skills except the users with the role of freelancer
has_many :roles, through: :user_roles
def role?(role)
roles.any? { |r| r.name.underscore.to_sym == role }
end
end
thank you in anticipation.

You could do something like this:
class Skill < ApplicationRecord
belongs_to :user, -> { where role: 'freelancer' }
end
Keep in mind that this would save the skills for any role, but they would be visible only for freelancer.
You could also use cancancan to check whether the user is a freelancer.

Related

Forced validations for associated fields

I am using rails 5.0.0.1
When I submit a form, validations for associated fields are coming into action.
I have Gig, User, Category and other models
I am using devise for user authentication
Gig model
class Gig < ActiveRecord::Base
has_many :proposals
belongs_to :category
has_many :abilities
has_many :skills, through: :abilities
belongs_to :user
end
User model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :gigs
has_many :proposals
end
Category model
class Category < ActiveRecord::Base
has_many :gigs
end
When I try to create the gig in console, the transaction rolls back.
the error messages are
["Category must exist", "User must exist"]
I appreciate your help. Thanks in advance.
In rails 5 when you add belongs_to it makes this field required. Try this
belongs_to :user, optional: true

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

Create Association on Registration Devise

I currently have 3 models set up:
class User < ActiveRecord::Base
belongs_to :user_type, polymorphic: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable, :rememberable
devise :database_authenticatable, :registerable, :recoverable, :trackable, :validatable, :confirmable
end
class Teacher < ActiveRecord::Base
has_one :user, as: :user_type
end
class Student < ActiveRecord::Base
has_one :user, as: :user_type
end
I would like to know what the best way to, upon a user signing up, create either a Student or Teacher, that is automatically associated to the User.
The Student & Teacher models have different attributes, but a User must be either one or the other.
My initial thought was to do the registration through the Student/Teacher Model, and then call devise's create method within the Student/Teacher create method, although I'm not entirely sure how to do that as well.
As an aside, one this is set up correctly, how would I go about setting different redirect paths after sign in depending on whether the user is a Student or a Teacher?
Any help is appreciated, thank you!
I don't know what is the condition for it to be student or teacher, but you could do that on "before_create" callback.
For example, something like this on user model:
before_create :assign_role
def assign_role
//if condition, teacher.create or student.create
end
But have you considered to use inheritance, instead? Put User as superclass of student and teacher, and on then, instead of
class Teacher < ActiveRecord::Base
it would be
class Teacher < User
then on teacher/student model you would put the particular attributes and methods you want. I think it's more clean and ellegant. Good luck!

Multi-level Association in Rails?

I am working on a medical application. In it, I have associations between users and clients (obviously), and an association between users and treatments, and users and settings (for a settings table).
But the tricky part here is that the client also has to be associated to the treatments table, because they are the ones that have the treatments on their record. The user is simply the one administrating all of the above. And also we have patients who are associated to clients, so it will need to be multi-layered. So owners have clients who also have patients. And patients have treatments as do Clients and do owners.
It seems really complex to me and I am having a hard time getting anything beyond user working. I am using the basic relationship setup in Rails (i know very little about rails). I am using #treatment.user = current_user on the create method, and then simply associating the tables needed with a user_id. I put a client_id on the treatment table, but that won't work will it?
Do I need a polymorphic association (not sure what that is though)? OR do I need seperate tables to do all of this matching?
Thanks.
Code:
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, :role
validates :email, presence: true
has_many :clients
has_many :settings
has_many :treatments
ROLES = %w[admin receptionist practitioner]
def role_symbols
[role.to_sym]
end
def to_s
email
end
end
I am not totally sure yet, on what your problem is.
But since you mentioned you are not familiar with Rails, this might help you:
Have a look at the has_many :through relation (also available as has_one :through)
So you could probably do something like this:
# patient.rb
class Patient < ActiveRecord::Base
has_many :treatments, :through => :client
end

How can I move "has_many" associations and fields from one collection to another?

I'm quite new to RoR. Sorry if I'm using wrong terminology or the answer is obvious.
Initially I had one model for users as follows,
class User
include Mongoid::Document
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable,
:token_authenticatable,
:omniauthable
has_many :foos
field :name, :type => String
# Some other company fields
....
end
class Foo
include Mongoid::Document
belongs_to :user
...
end
This initial User model used to represent a company.
Then I decided to add another model which will have a different role from the initial User model, so I started using polymorphic associations and moved the necessary fields from User to Company model. I also added a Manager model which is not directly related to Company. I basically use User model for devise.
class User
include Mongoid::Document
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable,
:token_authenticatable,
:omniauthable
belongs_to :rolable, :polymorphic => true
end
class Company
include Mongoid::Document
has_one :user, :as => :rolable
has_many :foos
field :name, :type => String
# Some other company fields
....
end
class Manager
include Mongoid::Document
has_one :user, :as => rolable
end
class Foo
include Mongoid::Document
belongs_to :company
...
end
Everything seems to work fine so far for the new user registrations. However, there is the old database I have to convert. What confuses me is essentially the has_many association that I had before. I already implemented migration (using this gem, https://github.com/adacosta/mongoid_rails_migrations) to move the fields from User model to Company model, but again I couldn't figure out how to deal with the associations.
You are not required to run your migration if you don't need to transfer the information from your old database to your new one.
MongoDB can have some useless keys on document, there are no problems. The only problem you can have is to have extra octet saved on your database.

Resources