Uncertain about model association - ruby-on-rails

I'm working on a project that allows a user to create a company. If a user creates a company, the user will be the admin.
However I would also like that user to then be able to invite users to sign up. So that all the users will belong to that company.
So my question is that the company would technically I guess belong_to the admin. However the company also has many users.
What would be the right association setup for this?

You can have both a belongs_to and has_many relation to User from your Company model at the same time. Set an alias to separate them like this:
# app/models/company.rb
belongs_to :admin, :class_name => 'User'
has_many :users
Now you can access the admin user through #company.admin and the users through #company.users.

class Company
belongs_to :admin, :class_name => 'User', foreign_key: :admin_id
has_many :users
end
This should work. When creating the Company model, give
admin_id = #current_user.id
#current_user provided you are using Devise for authentication management.
Cheers,
Akhil

Related

Rolify scope roles to many objects and different classes Rails 6

I am trying to "extend" Rolify functionality to have some global roles such as 'Admin', 'Member', 'Guest', etc... and to be able to set up different "scopes" for each user who have a specific role.
For example, in my app i have this admin role, which is a "super role" meaning it grants access to basically everything. But i also want to be able to "scope" this role for another User, the scope will be, for example 'he will have access to all users, but only if they are from countries A, B, C and from cities X, Y, Z'. I know rolify supports different roles with different scopes, but what i want is to manage "global roles" with different scopes only for different users.
I thought about doing something like a 'Scope' model that belongs to a Role and to a User, in which i would have HABTM relationships with countries and cities, and then use that for authorization (I'm using CanCanCan). But i ran into many issues when working on this approach. It was something like:
class Scope
belongs_to :user
belongs_to :role
has_and_belongs_to_many :countries
has_and_belongs_to_many :cities
end
One of the issues i ran into was that i need to grant the role at the same time i create a scope, and if a user is 'revoked' of a role, the scope which belongs to the user and the role, needs to be destroyed. This last part i found particularly hard since 'Scope' is not related to 'users_roles' table.
Anyone has any idea on a better approach to this problem? I'm having a hard time figuring out the right way to have a role that has custom scopes for each user (basically i need something in the middle of the user and the role to define what is the user's scope with that role).
Appreciate any help I can get!
If you want to create something of your own has_and_belongs_to_many is not the answer (hint: it's almost never the right answer). Using HABTM is the akilles heel of Rolify as its assocations look like this:
class User
has_and_belongs_to_many :roles
end
class Role
has_and_belongs_to_many :users
belongs_to :resource,
polymorphic: true,
optional: true
end
This doesn't let you you query the users_roles table directly or add additional columns or logic. Fixing it has been an open issue since 2013. There are workarounds but Rolify may not be the right tool for the job here anyways.
If you want to roll your own you want to use has_many through: to setup an actual join model so you can query the join table directly and add assocations, additional columns and logic to it.
class User
has_many :user_roles
has_many :roles, through: :user_roles
end
class UserRole
belongs_to :user
belongs_to :role
belongs_to :resource,
polymorphic: true,
optional: true
validates_uniqueness_of :user_id,
scope: [:role_id, :resource_id, :resource_type]
end
class Role
validates :name, presence: true,
uniqueness: true
has_many :user_roles
has_many :roles, through: :user_roles
end
This moves the resource scoping from being per role to being per user.
While you could add additional join tables between the user_roles table and the "scoped" resources its not strictly necissary unless you want to avoid polymorphic asssocations.

Inheriting an association via another model in Rails 5

I have a pretty standard User/Role setup going on (a user HABTM roles, a role HABTM users). I'm using CanCanCan for authorisation, and the role you have defines what you can do around the application. This part is all working fine, but now I want to be able to have users inherit roles as part of having a subscription to different memberships.
Here are the models concerned:
class User < ApplicationRecord
has_and_belongs_to_many :roles
has_one :membership_subscription
has_one :membership, through: :membership_subscription
end
class Role < ApplicationRecord
has_and_belongs_to_many :users
end
class MembershipSubscription < ApplicationRecord
belongs_to :user
belongs_to :membership
end
class Membership < ApplicationRecord
has_many :membership_subscriptions
has_many :users, through: :membership_subscriptions
end
I was thinking that I might be able to just add a has_many: roles association to the Membership, and then say that the user has_many roles through their subscription to the Membership, as well as the current HABTM association that allows roles to be assigned directly.
This way you can directly attach roles to users like you can now (as some roles are additive, and not related to the membership subscription/type at all) but also users will automatically inherit roles (and lose them again) as their membership subs come and go.
Does that make sense? I guess the other option would be to use callbacks in the model to deal with creating/deleting role associations but it doesn't seem as elegant.
Any advice greatly appreciated!
Okay so I think this is a valid answer:
First, update the models so that there is an associations between the Memberships and the Roles:
class Role < ApplicationRecord
has_and_belongs_to_many :users
has_and_belongs_to_many :memberships
end
class Membership < ApplicationRecord
has_many :membership_subscriptions
has_many :users, through: :membership_subscriptions
has_and_belongs_to_many :roles
end
Next, create a method in the user model that can be used to retrieve both directly assigned roles and inherited roles:
def combined_roles
if self.membership == nil
self.roles
else
self.roles + self.membership.roles
end
end
Then wherever you need to check a role, call that method instead of the usual user.roles
Not sure if that's a naive way of doing things, but seems to work okay. Comments still welcome if there's a better way
EDIT:
This allows a user to have the same role multiple times - it can be assigned directly or inherited. Modify the combined_roles method like so so that it strips out duplicates:
def combined_roles
if self.membership == nil
self.roles
else
(self.roles + self.membership.roles).uniq
end
end

How to make a resource that belongs_to multiple users in Rails

I'm setting up an app that has Users and Brands. Most users will not be associated with a brand, and will only be able to comment on Brand pages. Some users, however, will be associated with a single brand. I want these users to be the "admins" or owners of this brand. E.g. Users A and B are both "admins" of a brand, and so can create/edit/update the brand, etc. My question is, how should I set up the Brand resource such that it "belongs_to" multiple users? I understand that I could say brands have_many users, but is it weird to say that an object "has" a user? Is it more appropriate to "belong" to users? This description leads me to believe so: "For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier."
It's definitely a has_many relationship.
But it may be clearer to refer to those special users as 'administrators' or 'admins'
class Brand
has_many :administrators, class_name: 'User'
end
If it turns out that a user can be administrator for several brands, then you'll need a join table, either HABTM or HMT. HMT is the better choice in case you want to store characteristics about the join (e.g. when he became administrator)
class BrandUser
belongs_to :user
belongs_to :brand
end
class Brand
has_many :brand_users
has_many :administrators, through: :brand_users, source: :user
end
class User
has_many :brand_users
has_many :brands, through: :brand_users
end

ActiveRecord relationship model with Users and Organizations

I'm trying to find out what's the best logical way to model relationship between models.
I have 4 models:
User
Product
SlackTeam
Organization
Here User has many Products, SlackTeams and Organizations, and SlackTeam belongs to User and has one Organization. Organization should belong to User and SlackTeam. Am I logically correct here?
The workflow is following:
Users can log in with SlackTeam (which automatically creates Organization)
other Users from the same slack team will be added to same Organization once they link up their account with Slack
if Users are connected to many SlackTeams (and Organizations) they can filter to see Products from all Organizations they are part of or only from one
Am I missing something?
class User
has_many :users_ogranizations
has_many :organizations, through: :users_organizations
has_many :products, through: :organizations
end
class Product
belongs_to :organization
end
class Organization
has_many :users_ogranizations
has_many :users, through: :users_organizations
has_many :products
end
class UsersOrganization
belongs_to :user
belongs_to :organization
end
# i'd rather use slack profile than team, because Organization and Team
# already connotes the same thing.
class SlackProfile
end
You can handle your user's login however you like, I would prefer a kind of authentication service, though. All products that belongs to the organization is now accessible to the user, you can then filter the products with:
current_user.products.where(organization: Organization.last)

Rails "Sometimes Has One" Relationships

This is probably a newbie question, but I can't seem to think of a good solution. I have a company table that has_many users through groups that can also be administrators of the company (enabling them to edit the company but only one company per user).
What's the best way to set this up in Rails?
I can't add an admin field to the user table, because it wouldn't discriminate which company he/she is administrating. But if I do a company_id field, what would that relationship look like in Rails (since it's a sort of somtimes_has_one relationship!). I could leave it without a relationship, but that doesn't seem proper...
Thanks in advance for any help!
From what I understand, you have a user which might belong to a company, and if it does, it might actually administer it.
You could setup Group to have for example, company_id, user_id and an admin field (this way you get to know which users belong to which company, and if they also administrate that company)
For a user to belong to just one company you could add a validation for uniqueness per two columns (company_id and user_id)
You could get one company's administrators by doing
class Company < ActiveRecord::Base
has_many :groups
has_many :users, through: :groups
has_many :administrators, through: :groups, source: :user, conditions: ["groups.admin = ?", true]
end
and call company.administrators or company.users for all users
You could also do something like
class User < ActiveRecord::Base
has_one :group
has_one :company, through: :group
has_one :administered_company, through: :group, source: :company, conditions: ["groups.admin = ?", true]
end
so you can call user.company or user.administered_company
and so on...

Resources