Let's say we have coaches, clients, and users.
What's the ideal way to model this in a way that isn't inheritance? I'd like to avoid STI.
Right now I have something like this:
user.rb
has_many :coaches, :foreign_key => :client_id
has_many :coach_users, :through => :coaches, :source => :user
has_many :clients, :class_name => "Coach"
has_many :client_users, :through => :clients, :source => :client
def is_a_coach_of?(client)
self.client_users.include?(client)
end
def is_a_client_of?(coach)
self.coach_users.include?(coach)
end
coach.rb
belongs_to :user
belongs_to :client, :class_name => "User"
But this feels really clunky to deal with a User object that is supposedly a 'coach' and having to type user.coach_users to get a collection of users that are being coached by this specific user.
It feels very non idiomatic and quite honestly, it's just plain confusing and I hate it. I want something more elegant.
I thought of removing the join model and just having two has_many's on the user.rb model but it still feels clunky, especially the icky feeling of violating roles of objects. These are different roles but are also very similar because they're all a user. How do you separate such common logic in an elegant way, in the right idiomatic way with Rails and Ruby?
A "user of the site" can exist without being a coach or a client.
If the modeling requires just a relationship, then I can see it be a HABTM but what if the individual relationship requires extra logic? E.g extra logic on client or coach? Would you just mixin a class that defines logic in the User model? Or would you create separate AR models for the relationship and if so, how?
If a client/coach is just a relationship, it can be just that, not a separate model. So you can do a has_and_belongs_to_many relationship between Users. Create a migration with:
def up
create_table :coaches_clients do |t|
t.integer :coach_id
t.integer :client_id
end
end
and in you model:
has_and_belongs_to_many :clients,
:foreign_key => 'client_id',
:association_foreign_key => 'coach_id',
:class_name => 'User',
:join_table => 'coaches_clients'
has_and_belongs_to_many :coaches,
:foreign_key => 'coach_id',
:association_foreign_key => 'client_id',
:class_name => 'User',
:join_table => 'coaches_clients'
Related
So lets I have a Transactions model.
Transactions.rb has:
belongs_to :buyer, :class_name => "User"
belongs_to :seller, :class_name => "User"
The user logged in, is accessed with current_user.
How can I do something like current_user.transactions? (which won't work as transactions doesn't have a user_id column) Or something like current_user.transactions.buyer?
Thanks!
(also the user model has_many :transactions)
All associations in Rails are one-way.
So for each belongs_to, you need to add a has_many or has_one on the other side.
I'd suggest you want something like this;
class User
has_many :transactions_as_buyer,
:class_name => "Transaction",
:foreign_key => :buyer_id
has_many :transactions_as_seller,
:class_name => "Transaction",
:foreign_key => :seller_id
end
Now you can say;
current_user.transactions_as_seller.map(&:buyer)
to get an array of buyers.
Of course, depending on your app you may have a better name than "transactions_as_buyer/seller"
I have a parent/child relationship via our users table, with models as such:
class User < ActiveRecord::Base
# Parents relationship
has_many :children_parents, :class_name => "ParentsChild", :foreign_key => "child_id", :dependent => :destroy
has_many :parents, :through => :children_parents
# Children relatiopnship
has_many :parents_children, :class_name => "ParentsChild", :foreign_key => "parent_id", :dependent => :destroy
has_many :children, :through => :parents_children
...
end
And in parents_child.rb:
class ParentsChild < ActiveRecord::Base
belongs_to :parent, :class_name => "User"
belongs_to :child, :class_name => "User"
end
Right now, it is possible in our "add children" form (just using vanilla nested attributes) to add the same user as a child multiple times for parents. I am not sure what the 'right' way to go about forcing uniqueness in the ParentsChild relationship, although I am leaning towards a unique index on (parent_id, child_id) at the database layer (using a migration of course).
I am sure I could also enforce uniqueness constraints in the UsersController::update method, but would prefer to avoid changing that code (right now it doesn't reference parents/children at all, thanks to nested attributes in the form/model) if possible. I am most concerned with making sure we use the "proper" solution. What is the 'right' or 'rails' way to do this?
Using has_many :through, you can specify :uniq as an option, like this:
has_many :parents, :through => :children_parents, :uniq => true
Basically, I have a users model in my rails app, and a fanship model, to facilitate the ability for users to become 'fans' of each other.
In my user model, I have:
has_many :fanships
has_many :fanofs, :through => :fanships
In my fanship model, I have:
belongs_to :user
belongs_to :fanof, :class_name => "User", :foreign_key => "fanof_id"
My fanship table basically consists of :id, :user_id and :fanof_id. This all works fine, and I can see what users a specific user is a fan of like:
<% #user.fanofs.each do |fan| %>
#things
<% end %>
My question is, how can I get a list of the users that are a fan of this specific user?
I'd like it if I could just have something like #user.fans, but if that isn't possible what is the most efficient way of going about this?
Thanks!
Add in User model:
has_many :my_fanclubs, :class_name => 'Fanship', :foreign_key => 'fanof_id'
has_many :fans, :through => :my_fanclubs, :source => :user, :class_name => 'User'
(not tested)
I run the risk of palm-to-forehead here, but I can't quite figure out how to do this with Rails' ActiveRecord sugar.
I have a tickets table that has two columns (submitter_id and assignee_id) that should each reference a different user from the users table (specifically the id column in the users table). I'd like to be able to do things like ticket.submitter.name and ticket.assignee.email using ActiveRecord's associations. Submitter and Assignee are simply user objects under different associative names.
The only thing I've found that comes close to what I am doing is using polymorphic associations, but in the end I'm fairly certain that it's not really what I need. I'm not going to have multiple types, both submitter and assignee will be users, and very well could be two different users.
Any help would be fantastic. Thanks!
class Ticket < ActiveRecord::Base
belongs_to :submitter, :class_name => "User"
belongs_to :assignee, :class_name => "User"
end
Should work.
Edit: Without trying it out, I'm not sure whether you need the :foreign_key parameter or not. My instinct is not, but it couldn't hurt.
Edit again: Sorry, left off the User -> Ticket associations. You didn't mention using them, and I typically will only add associations in one direction if I don't plan on using them in the other direction.
Anyway, try:
class User < ActiveRecord::Base
has_many :assigned_tickets, :class_name => "Ticket", :foreign_key => "assignee_id"
has_many :submitted_tickets, :class_name => "Ticket", :foreign_key => "submitter_id"
end
Something like this should work
class Ticket < ActiveRecord::Base
belongs_to :submitter, :class_name => 'User', :foreign_key => 'submitter_id'
belongs_to :assignee, :class_name => 'User', :foreign_key => 'assignee_id'
end
class User < ActiveRecord::Base
has_many :tickets, :class_name => 'Ticket', :foreign_key => 'submitter_id'
has_many :tickets_assigned, :class_name => 'Ticket', :foreign_key => 'assignee_id'
end
Yes, PreciousBodilyFluids is right we don't need to specify the foreign_key in the Ticket class as rails can infer it from the column name, i.e. submitter_id and assignee_id
But if your association name is different from the column_name_{id} then you will have to specify it, i.e. the User class case
I have a Rails application that I'm in the process of designing. I have a separate model that needs to link to only 2 of one model. Specifically, my "evaluation"s have 2 "member"s, an evaluator, and an evaluatee. They also have a few other pieces of information, too but they should not be relevant to this.
What is the best way to represent this? Would 2 foreign keys in the evaluation be best, or a many-many relationship between the evaluations and the members? Would there be some other option that would work even better?
I would initially think many to many, but since there is a defined number on one side of the relationship I question the applicability here. To my knowledge, many-to-many generally implies that the number on each side of the relation is variable.
You probably want two different associations, possibly with the same class:
class Member < ActiveRecord::Base
has_many :evaluations_out, :class_name => 'evaluation', :as => :evaluator
has_many :evaluations_in, :class_name => 'evaluation', :as => :evaluatee
end
class Evaluation < ActiveRecord::Base
belongs_to :evaluator, :class_name => 'member'
belongs_to :evaluatee, :class_name => 'member'
end
I haven't tested it myself and it might sound a little adventurous, but I think that could work:
Evaluation Model
class Evaluation < ActiveRecord::Base
belongs_to :evaluator, :class_name => "Member", :foreign_key => "evaluator_id"
belongs_to :evaluatee, :class_name => "Member", :foreign_key => "evaluatee_id"
end
Member Model
class Member < ActiveRecord::Base
has_many :evaluators, :class_name => "Evaluation", :foreign_key => "evaluator_id"
has_many :evaluatees, :class_name => "Evaluation", :foreign_key => "evaluatee_id"
end