I have a User and a Event model. I want to be able to associate each event with multiple attending users, and then have another user who is also among the attendees, be labeled as the owner, such that I would be able to make calls like #event.users, to retrieve all attendees, #event.owner, to retrieve the owner and then also be able to call #user.events, to get the events the user is attending.
Would it be most optimal to create a third model called Events_Users that keeps track of the relationship between users and events by storing a user_id together with an event_id, or just update the existing Event model with a user_id, along with the owner_id?
Please, some concrete suggestions will be much appreciated
Thanks
I would do it like this.
class Event < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
has_and_belongs_to_many :attendees, class_name: 'User'
end
This way, you will have reference id to user in your events table (owner), and there will be join table for typical HABTM relationship for Users/Events (attendees for event).
Hope it helps!
Update
Here's associations for User class:
class User < ActiveRecord::Base
has_many :events
has_and_belongs_to_many :attended_events, class_name: 'Event'
end
Update 2
Here's the link to Rails Guide to Associations. It will explain how to create appropriate tables and columns for these kinds of relationships.
Related
I'm working on an event site where users have items in their inventory that can be listed in their profile. For this I am using:
has_many :items
in my user.rb.
A user would then be able to attend any number of events. For each event, they would have a unique items list, i.e., items to bring to the event. I'm trying to figure out the associations in order to make this work.
In item_list.rb:
belongs_to :event
belongs_to :user
has_many :items
In item.rb:
belongs_to :user
belongs_to :item_list
In event.rb
has_many :item_lists
But what's baffling me is making sure that each list is unique to each event and user. Additionally, would my migration for item_list include an array of items?
Any insight would be appreciated.
But what's baffling me is making sure that each list is unique to each
event and user.
If I'm not wrong, you are looking for validates_uniqueness_of with scope option.
In your item_list.rb, add
validates_uniqueness_of :event_id, scope: :user_id
This will ensure you have an item_list with unique event_id and user_id. In other words, each item_list is unique to each event and user.
When I generate my database migration for item_list, would I need to
include a column of arrays, i.e. to hold item_ids
No, with how your associations are setup Rails will expect you to have item_list_id in items table. So if you want fetch items for an item_list, you would do #item_list.items
Question: How can I return Assignments associates with one of many users in the users array?
I researched the Rails guides and some only posts but I can't figure this out yet.
https://codereview.stackexchange.com/questions/46319/is-there-a-better-approach-to-searching-has-and-belongs-to-many-relations
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches
I am associating users to assignments two different ways.
1- user "user_id" is the one who creates the assignment
2- The assignment is given to multiple users. Users are associated to assignments using has_and_belongs_to_many :users
Basically each assignment is associated to the user who owns the task.
The assignment is also given to multiple users who will work on it.
I can successfully return all tasks associated with user but not with users.
I'm trying to display only the tasks associated with the current_user (devise)
This works for user:
assignment.rb
class Assignment < ActiveRecord::Base
belongs_to :deliverable
belongs_to :user
has_and_belongs_to_many :users
end
user.rb
has_and_belongs_to_many :assignments
The association are working fine. In the console I can get all the users associated via HABTM to the assignment.
I have a designer dashboard where i only want to display assignments given to the current user.
designer_dashboard controller:
#if I do this I'll get all the assignments:
#assignments = Assignment.all
# but I want to be able to do something like this to get only the assingments associated with the current user via HABTM
#assignments = Assignment.includes(:users).where(["user_ids =?", current_user])
The data isn't modelled to reflect the 2 different types of relationship that exist between users and tasks - task owners and task designers. You've only set up one of them.
You will need to remodel the data and give the relationships more meaningful names.
One way would be to use has_many_through for the association that a Task has with who its assigned to. A Task has_many Designers through AssignedTasks. The association between Task and User can be named as TaskOwner. If you set up both these associations you will be able to get current_user.owned tasks and current_user.assigned tasks which is more clear than referring to user and users.
class Task
belongs_to :task_owner, class_name: "User"
has_many :assigned_tasks
has_many :designers, through: assigned_tasks, class_name: "User"
end
class User
has_many :owned_tasks, class_name: "Task"
has_many :assigned_tasks, foreign_key: designer_id
has_many :tasks, through: :assigned_tasks,
end
class AssignedTask
belongs_to :designer
belongs_to :task
end
You will need to generate some migrations to add the requisite ids.
Also, I seem to remember reading somewhere that Task is a reserved word. You may want to rename task to something else.
Margo answer is correct.
This works in controller:
#assignments = current_user.assignments
In my Rails app, I have the following models:
class User < ActiveRecord::Base
# user declaration
has_many :account
end
class Account < ActiveRecord::Base
belongs_to :user
end
I need to add another relation where each Account can be managed by multiple AccountManagers. However, AccountManagers themselves are also Users of this system (i.e. a User can both have an Account and manage another user's account).
I'm fairly new to Rails, and I know that I can just create another model called AccountManagers. I have a feeling that we don't NEED to make another model however; all the information contained within my proposed AccountManagers model is found in the Users model as well.
I've tried to add the following relationship to the Account model:
has_many :account_managers, through: :users, source: :users
where the Account has many managers, and each manager is declared from the User model. This doesn't work as the AccountManagers table doesn't exist (and the error in the view states that as well).
Is there a way to get this relationship to work?
You have to add another join table, say account_managements with columns and user_id and account_id
class User < ActiveRecord::Base
# user declaration
has_many :accounts
has_many :managed_accounts, :source => :account, :through => :account_managements
end
class Account < ActiveRecord::Base
belongs_to :user
has_many :account_managers, :source => :user, :through => :account_managements
end
and
class AccountManagement < ActiveRecord::Base
belongs_to :user
belongs_to :account
end
You don't need to add another class AccountManager, You can add one more relation like this:
class User < ActiveRecord::Base
# user declaration
has_many :account
has_many :managed_accounts, :class_name => 'Account', :primary_key => :account_manager_id
end
class Account < ActiveRecord::Base
belongs_to :user
belongs_to :account_managers, : class_name => :User, :foreign_key => :account_manager_id
end
For this you will need to have account_manager_id in the accounts table.
The main issue I can see here is that a user has_many accounts, but in ur example, an account only has 1 user. Are u planning to have accounts with only 1 person in them?
In relational tables there are 2 main kinds of table designs.
A. One to Many
U have a relationship where one thing has many of another thing, for instance: a Owner has many Cats. In this type of relationship the Cat table can point to the Owner table. Clearly the Owner cannot point to its cats because u would need to have a pointer for each cat. it would be something like
Owners table
cat_1
cat_2
cat_3
thats not convenient at all, since there is a maximum number of cats.
If on the other hand u have
cats table
owner_id
then each owner can have an unlimited amount of cats.
More complex
After some time u get a request, some owners share a cat. u think about it a while and decide a cat can only belong to a max of 2 owners.
so u change the cat table.
cats table
owner_1
owner_2
B. Many to Many
If you want to be able to allow a cat to have any unlimited number of owners, or a owner to have an unlimited number of cats, u will need a third table. This table keeps a link from 1 cat to 1 owner. Each row defines this relationship. This table can be named either using the names of the other 2 tables: cat_owners or since this table defines a relationship u can give it a name that defines this relationship.
In this case the relationship is Ownership, people own cats. Its hard to say how the cats would define the relationship :)
This brings me to answer ur question finally. If u have a table that defines the link between a user and an account, I like the name Membership
Membership
user_id
account_id
but as u just mentioned there are some users in an account who are Managers, u can add this flag to the membership table.
Membership
user_id
account_id
manager (true/false)
u could take it a step beyond that and change manager, to a role column, and then every user can have a different role in every account.
What if each user can have multiple roles in each account? Then u will need more tables
Rails doesnt mean u can skip understanding relational databases structure.
So I have an application with users/user-profiles. Presently, users can view others profiles, send messages, and favorite user profiles. I'd like to also add the feature to allow users to 'hide-user' profiles so that they won't see the user ever again in search, or anything. And provide the option in 'settings' to 'un-hide' the user as well.
How might I do this? I haven't a clue as to where to begin with this feature.
(If you need any code examples, models, controllers please ask and I will happily provide)
Kind regards,
Sonny
There are probably a couple of ways to do this, the first approach that comes to mind would be to establish a self-referencing many to many relationship.
You will need to create the join table (I shall call it suppressed_users). I will show the rails model, as the migration wouldn't have anything other than the foreign keys.
class SuppressedUser < ActiveRecord::Base
belongs_to :user
belongs_to :suppressed_user, :class_name => "User", :foreign_key=>"suppressed_user_id"
end
And in the User model, in order to help DRY up your code, you can use a scope to easily filter all the users that this target user has decided to suppress (or hide):
class User < ActiveRecord::Base
has_many :suppressed_users // Optional
scope :without_hidden_users, -> (target_user) do
where.not("exists (?)",
SuppressedUser.select("1")
.where("users.id = suppressed_users.suppressed_user_id AND suppressed_users.user_id = ?", target_user))
end
end
Note about the scope: What I'm doing here is creating a dependent (or correlated) subquery, in which I check whether the target user has suppressed (or hidden) the user we're looking at at the moment. In other words, the dependent subquery is executed for each row in the users result set (those not filtered by other where or join conditions and such). With proper indexing, this should not have an impact on performance.
Note about has_many :suppressed_users: This is technically not needed for the query I've shown, so if it is not relevant for anything in your system, you should be safe to remove it.
So, if I am presently logged in, and I want to search for a list of users meeting some condition, in your controller you would do something like this:
User.without_hidden_users(#current_user.id)...other conditions and such as needed
Assuming #current_user represents the currently logged in user.
I believe one approach would be to create a many_to_many relationship via the has_many :through association between users and hidden users. And likewise another many_to_many relationship between users and hiders (i.e. users who are hiding the user). In the end, you should be able to do something like this:
some_user.hidden_users and some_user.hiders (i.e. all the users that are hiding some user). You probably won't need the second one most of the time.
So the first thing to do would be to create a join table called hiders_hidden_users (or whatever you want) which would contain only two fields: hider_id and hidden_user_id.
Note, that in reality, those ids will both refer to a User record. Your HidersHiddenUser model will look something like this:
class HidersHiddenUsers < ActiveRecord::Base
belongs_to :hidden_user, class_name: "User", foreign_key: "hidden_user_id"
belongs_to :hider, class_name: "User", foreign_key: "hider_id"
end
Then, you need to set up the relationships in the User class:
class User < ActiveRecord::Base
has_many :hiders_join, class_name: "HidersHiddenUser", foreign_key: "hider_id"
has_many :hidden_users_join, class_name: "HidersHiddenUser", foreign_key: "hidden_user_id"
has_many :hiders, through: :hiders_join
has_many :hidden_users, through: :hidden_users_join
end
Note, that you have to specify the class name and foreign key when writing the has_many relationship with the join table. Note, also that you have to specify the relationship twice with the same model.
Then, say some_user wants to hide user1 and user2. All you would need to do is something like this:
some_user.hidden_users << user1
some_user.hidden_users << user2
Although I have not tested this, I believe it should work.
I'm trying to implement something similar to that below. Basic setup is a Schedule model
class Schedule < ActiveRecord::Base
has_many :events
end
The Event model will then belong_to a Schedule.
Events are comprised of a name, datetime, running length and a Room
A Room is chosen from a select list when the event is created, all Rooms are created beforehand through seeding or admin interface. Room will store information like seating count.
I've been trying to find a method implementing this that feels right. Solutions seem to range between habtm or has_many :through but I can't see the need for a join table for this situation.
Theoretically, an Event has_one :room but the reverse relationship isn't belongs_to :event as a Room may be used for many events, this also requires the foreign key to be on the rooms table.
I've considered handling this manually in the model using a room_id foreign key in the event, I could then query for the relevant Room. I think this would work since I currently cannot see a requirement for finding all events using a Room.
class Event < ActiveRecord::Base
belongs_to :schedule
def room
Room.find(room_id)
end
end
Everything I've done so far in Rails has felt 'right', but all the solutions I've come up with here doesn't and I feel like I'm missing something; or maybe I'm just expecting that extra bit of magic.
Is there a "Rails" way to do this?
Wouldn't Event just have a belongs_to relationship to Room in this case?
class Event < ActiveRecord::Base
belongs_to :schedule
belongs_to :room
end
If you think about it from a schema perspective, your "events" table almost certainly has "schedule_id" and "room_id" columns.
The other side of the relationship is that a Room has_many Events.