In my app, an Account can be owned by a Household or a User. Users can access accounts that they own, and accounts that their household owns. I've defined accessible_accounts, that gives me an array of both household and user accounts, but is there a way to get the same result as a relation, so I can chain it with further conditionals? The order is unimportant (and indeed can be set with further chaining)
class User < ActiveRecord::Base
has_many :accounts, as: :owner
belongs_to :household
def accessible_accounts
ua = accounts.to_a
ha = []
if household
ha = household.accounts.to_a
end
(ua + ha).uniq
end
end
class Household < ActiveRecord::Base
has_many :users
has_many :accounts, as: :owner
end
class Account < ActiveRecord::Base
belongs_to :owner, polymorphic: true
end
I have a couple of thoughts on this:
First, you could express the Account that User has through Household by adding the following to the Accounts model:
has_many :accounts, through: household
However, I understand that you want a Relation that represents the merge/union of the accounts that a user owns directly with the accounts they own through their associated household. If that's true, then I think the following method added to User will give you what you want:
def accessible_accounts
Account.where(
'(ownable_id = ? and ownable_type = ?) or (ownable_id = ? and ownable_type = ?)',
id, User.to_s, household_id, Household.to_s)
end
I have not tested this, but I thought I'd go ahead and share it and count on feedback if I've misunderstood something.
In a proper polymorphic association I think your structure would be as following:
class User < ActiveRecord::Base
belongs_to :household
has_many :accounts, as: :ownable
end
class Household < ActiveRecord::Base
has_many :users
has_many :accounts, as: :ownable
end
class Account < ActiveRecord::Base
belongs_to :ownable, polymorphic: true
end
By the way, do you have any speacial reasons for not using Devise and CanCan for authentication & authorization?
Related
I'm working on a Rails 5.2 project that stores and manages guest lists. I have Event and Guest models, and they are associated with a HABTM relationship. This works well, but there is a requirement to be able to optionally store a grouping of two guests (i.e: couples) and when adding guests to the guest list, the couple can be selected and added together, without the user having to remember which of the individual guests should be added to the guest list together, for example, when selecting guests to be added to a guest list, a user should be able to select "Sam", "Andrew", "Mary & Joseph".
What would be the best way of achieving this in ActiveRecord?
class Event < ApplicationRecord
has_and_belongs_to_many :guests
end
class Guest < ApplicationRecord
has_and_belongs_to_many :events
end
Any help would be much appreciated!
Thanks
You need the following models, untested but you'll get the idea.
class Event < ApplicationRecord
has_many :event_guests
end
class Guest < ApplicationRecord
has_many :event_guests, :as => :assignable
has_many :guest_couples
end
class Couple < ApplicationRecord
has_many :event_guests, :as => :assignable
has_many :guest_couples
end
# table to relate events to either a Guest or a Couple (polymorhpic)
class EventGuest < ApplicationRecord
belongs_to :event
belongs_to :assignable, polymorphic: true
end
# Model to create couples (one-to-many)
class GuestCouple < ApplicationRecord
belongs_to :guest
belongs_to :couple
end
A user belongs to an organization, which in turn can have multiple users and child organizations. How do you find all the organizations users?
I have the models named User and Organization. They have the following relationships:
In the user model:
belongs_to :organization
In the organization model:
has_many :users
has_many :child_organizations, class_name: "Organization", foreign_key:"parent_id"
belongs_to :parent, class_name: "Organization"
I want to find all users who belong to child_organizations of the current user organization.
#users = current_user.organization.child_organizations.users
It returns this error:
undefined method `users' for Organization::ActiveRecord_Associations_CollectionProxy:0x8f975d0
Based on the formatting of your question I'm not entirely sure what it is you have for you model relationships. But if you want to find all users whom belong to child_organizations of current_user's organization ...
This is how you can set up your relationships
class User < ActiveRecord::Base
belongs_to :organization
belongs_to :child_organization
end
class Organization < ActiveRecord::Base
has_many :child_organizations
has_many :users, through: :child_organizations
end
class ChildOrganization < ActiveRecord::Base
belongs_to :organization
has_many :users
end
And now you can use the following
#users = current_user.organization.users
I need to do two associations in the same model. Where:
Team has_many User
Now, I want that Team has_one Leader
This "Leader" will be a User
Im trying to use has_one throught but I think that association isn't work.
Leader.rb
class Leader < ActiveRecord::Base
belongs_to :user
belongs_to :team
Team.rb
class Team < ActiveRecord::Base
has_one :user, through: :leader
end
User.rb
class User < ActiveRecord::Base
belongs_to :team
has_one :captain
end
and the get following error around line 27:
NoMethodError in TeamsController#create
26 def create
**27 #team = current_user.teams.create(team_params)**
28 #team.save
29 respond_with(#team)
30 current_user.update(team_id: #team.id)
In this case I think you need 2 model are enough
1). User model
class User < ActiveRecord::Base
belongs_to :team
end
2). Team model
class Team < ActiveRecord::Base
has_many :users
belongs_to :leader, class_name: 'User', foreign_key: :leader_id
end
How about setting a boolean flag in users table called leader. And then your association can become:
class Team < ActiveRecord::Base
has_many :users
has_one :leader, class_name: 'User', -> { where leader: true }
end
Team has_many User Now, I want that Team has_one Leader
This "Leader" will be a User
Use inheritance (also called sub-classing), Leader is a User.
class User < ActiveRecord::Base
belongs_to :team
end
class Leader < User
end
class Team < ActiveRecord::Base
has_many :users
has_one :leader
end
Your users table is also important. Ensure that users has t.belongs_to :team and t.string :type in its create_table method. Note that a Leader is a User and does not need a separate table, however you do need to allow ActiveRecord to record its type so it can return the correct Model later.
References:
inheritance specifically you need 'single table inheritance'
belongs_to scroll down for has_one and has_many, the three relationships used here.
current_user.teams.create(team_params)
Teams is for a has_many association, you want current_user.create_team(team_params)
You have has_one association between user and team. Try this:
current_user.create_team(team_params)
Also, you should add proper back association from team to leader.
class Team < ActiveRecord::Base
belongs_to :leader
has_one :user, through: :leader
end
We have a Company, CompanyUser, User and Rating model defined like this:
Company model
class Company < ActiveRecord::Base
has_many :company_users
has_many :users, through: :company_users
has_one :company_owner, where(is_owner: true), class_name: 'CompanyUser', foreign_key: :user_id
has_one :owner, through: :company_owner
end
There is an is_owner flag in the company_users table to identify the owner of the company.
CompanyUser model
class CompanyUser < ActiveRecord::Base
belongs_to :company
belongs_to :user
belongs_to :owner, class_name: 'User', foreign_key: :user_id
end
User model
class User < ActiveRecord::Base
has_many :company_users
has_many :companies, through: :company_users
has_many :ratings
end
Rating model
class Rating
belongs_to :user
belongs_to :job
end
I am able to find the owner of a company, by the following code:
#owner = #company.owner
I need to get the ratings and the jobs of the owner along with the owner. I can do this
#owner = #company.owner
#ratings = #owner.ratings.includes(:job)
But we have already used #owner.ratings at many places in the view, and it is difficult to change all the references in the views as it is a pretty big view spanning in several partials. I tried the following to get the ratings along with the owner
#owner = #company.owner.includes(:ratings => :job)
But this gives me error as #company.owner seems to give a User object and it does not seem to support chaining.
Is there a way I can get the included associations (ratings and job) inside the #owner object?
You should be able to do this with:
#owner = Company.where(id: #company.id).includes(owner: {ratings: :job}).owner
However this is not very clean. Much better would be to actually change #company variable:
#company = Company.includes(owner: {ratings: :job}).find(params[:company_id]) # or params id or any other call you're currently using to get the company.
Company built that way will already have everything included, so:
#owner = #company.owner
will pass a model with preloaded associations.
I am using Ruby on Rails 3.0.7 and I would like to know how to retrieve the Active Record Association name between two classes\models.
That is, I have two models
class User < ActiveRecord::Base
has_many :accounts
end
class Account < ActiveRecord::Base
belongs_to :users
end
and I would like to retrieve (on runtime) them association name, in this case accounts and users strings.
Is it possible? If so, how can I do that?
UPDATE
If I have more association statements in User and Account classes (see the below example), how can I retrieve exactly the User Account association name?
class User < ActiveRecord::Base
has_many :accounts
has_many :articles
has_many :comments
end
class Account < ActiveRecord::Base
belongs_to :users
has_many :articles
belongs_to :authorization
end
?
User.reflect_on_all_associations.each do |assoc|
puts "#{assoc.macro} #{assoc.name}"
end
#=> "has_many accounts"
UPD
User.reflect_on_all_associations.select{|a| a.class_name == "Account"}.each do |assoc|
puts "#{assoc.macro} #{assoc.name}"
end
#=> "has_many accounts"