EDIT
Simple relationship but I'm having an issue getting it to work. There is a User. User's have many Bounties. User's have many BountyVotes through Bounty. Bounties have BountyVotes. For readability, I call BountyVotes -> Votes in the Bounty class. I get a Name Error: uninitialized constant User::bounty_vote when trying to access bounty_interests from the User model.
A user can create a Bounty. Other user's can vote on the Bounty.
//User class
class User < ActiveRecord::Base
has_many :bounties
has_many :bounty_interests, :through => :bounties, :source => :votes
end
//Bounty class
class Bounty < ActiveRecord::Base
belongs_to :user
has_many :votes, :class_name => :bounty_vote
end
//Bounty Vote class
class BountyVote < ActiveRecord::Base
belongs_to :bounty
end
Had to change two things. First, thanks to shakerlxxv I needed to change my through to be plural.
has_many :bounty_interests, :through => :bounties, :source => :votes
Than I also had to change the way I referenced my class name.
has_many :votes, :class_name => 'BountyVote'
Your :through clause needs to reference the plural form:
has_many :bounty_interests, :through => :bounties, :source => :votes
Related
Kind of a difficult concept to put into a title, but here is the use case:
I have users, the users can either belong to a partner or a customer. A partner can have many customers, but all users have a partner either directly or indirectly. Is there any way to create an association that would allow for partner access on any user regardless of whether or not they are directly related to it?
This is my current setup:
class User < ActiveRecord::Base
has_one :partner, through: :user_join, :source => :userable, :source_type => "Licensee"
has_one :customer, through: :user_join, :source => :userable, :source_type => "Customer"
end
class Partner < ActiveRecord::Base
has_many :customers
has_many :user_joins, as: :userable
has_many :users, through: :user_joins
end
class Customer < ActiveRecord::Base
belongs_to :partner
has_many :user_joins, as: :userable
has_many :users, through: :user_joins
end
This question already has an answer here:
Losing an Attribute When Saving Through an Association w/ Scope (Rails 4.0.0)
(1 answer)
Closed 9 years ago.
I want to model such a relationship between the models User and Event.
Therefore I have started with the following classes:
class User < ActiveRecord::Base
...
end
class Attendance < ActiveRecord::Base
# with columns user_id and event_id
...
end
class Event < ActiveRecord::Base
has_many :attendances
has_many :users, :through => :attendances
...
end
So far everything is okay: I can assign users and access attendances. But now I want to bring the state into play, such that I can distinguish e.g. between "attending", "unexcused absent", ... users. My first try was:
class Event < ActiveRecord::Base
has_many :attendances
has_many :users, :through => :attendances
has_many :unexcused_absent_users, -> { where :state => 'unexcused' },
:through => :attendances,
:source => :user
...
end
(:source has to be specified since otherwise it would search for a belongs to association named 'unexcused_absent_users')
The problem here is, that the where-predicate is evaluated on table 'users'.
I am clueless how to solve this 'correctly', without introducing new join tables/models for every state. Especially since every user can be just in one state for every event, I think a solution with one Attendance-model makes sense.
Have you an idea, how to get this right?
You can simply narrow the scope to look at the correct table:
has_many :unexcused_absent_users, -> { where(attendances: {state: 'unexcused'}) },
:through => :attendances,
:source => :user
Evem better, add this scope to the Attendance model and merge it in:
class Attendance < ActiveRecord::Base
def self.unexcused
where state: 'unexcused'
end
end
class Event < ActiveRecord::Base
has_many :unexcused_absent_users, -> { merge(Attendance.unexcused) },
:through => :attendances,
:source => :user
end
I have found a workaround, but I still think, this is ugly.
class Event < ActiveRecord::Base
has_many :user_attendances, :class_name => 'Attendance'
has_many :users, :through => :user_attendances, :source => :user
has_many :unexcued_absent_user_attendances, -> { where :state => 'unexcused'}, :class_name => 'Attendance'
has_many :unexcused_absent_users, :through => :unexcued_absent_user_attendances, :source => :user
end
In general: For every state that I want, I have to introduce a new has_many relationship with a scope and on top of that and an according has_many-through relationship.
this might work for you?
class Event < ActiveRecord::Base
has_many :attendances
has_many :users, :through => :attendances
def unexcused_absent_users
User.joins(:attendances)
.where(:state => 'unexcused')
.where(:event_id => self.id)
end
end
in rails 3+ methods are basically the same as scopes, just less confusing (in my opinion), they are chainable
event = Event.find(xxxx)
event.unexcused_absent_users.where("name LIKE ?", "Smi%")
What if I had 3 Models that I wanted to connect.
For example:
A user can have many different permissions for many different applications.
So I need a table to store:
user_id
permission_id
application_id
Is that possible with has_and_belongs_to_many?
Thanks
I would do it with a has_many :through.
class Upa < ActiveRecord::Base
belongs_to :user
belongs_to :permission
belongs_to :application
end
class User < ActiveRecord::Base
has_many :permissions, :through => :upas
has_many :applications, :through => :upas
end
class Permission < ActiveRecord::Base
has_many :users, :through => :upas
has_many :applications, :through => :upas
end
class Application < ActiveRecord::Base
has_many :permissions, :through => :upas
has_many :users, :through => :upas
end
examples of has_many :through
Basically any sort of relationship that you can describe with a classical one to one, one to many and many to many relationships in relational databases can be described in ActiveRecord.
Yes, you can have has_and_belongs_to_many relationship. More help can be found here http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
I have a User model which has many projects and a Project model which can have many users, but also belongs to a single user (ie the user who created this project). It must belong to a User. It also allows a list of users to be associated with it, think collaboration.
With this in mind, my models look like this:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
end
class AssignedProject < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Now, when I want to create a new project through a User, this is how I would do it:
user = User.create(:name => 'injekt')
user.projects.create(:name => 'project one')
Now, I know that projects is provided through an AssignedProject join model, which is why project.user will return nil. What I'm struggling to get my head around is the best way to assign the project creator (which by the way doesn't need to be user, it could be creator or something else descriptive, as long as it is of type User).
The idea then is to create a method to return projects_created from a User which will select only projects created by this user. Where user.projects will of course return ALL projects a user is associated with.
Assuming this kind of association is fairly common, what's the best way to achieve what I want? Any direction is greatly appreciated.
Add a creator_id column to your projects table for the creator relationship, and then add the associations to the models:
class User < ActiveRecord::Base
has_many :assigned_projects
has_many :projects, :through => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
belongs_to :user
has_many :assigned_projects
has_many :users, :through => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
I wanted to add little improvement to design. We don't actually need intermediate model because it does not contain any extra column other than reference_ids hence HABTM association is best suited over here.
class User < ActiveRecord::Base
has_and_belongs_to_many :projects, :join_table => :assigned_projects
has_many :created_projects, :class_name => "Project", :foreign_key => :creator_id
end
class Project < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :assigned_projects
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
end
Can't wrap my head around this...
class User < ActiveRecord::Base
has_many :fantasies, :through => :fantasizings
has_many :fantasizings, :dependent => :destroy
end
class Fantasy < ActiveRecord::Base
has_many :users, :through => :fantasizings
has_many :fantasizings, :dependent => :destroy
end
class Fantasizing < ActiveRecord::Base
belongs_to :user
belongs_to :fantasy
end
... which works fine for my primary relationship, in that a User can have many Fantasies, and that a Fantasy can belong to many Users.
However, I need to add another relationship for liking (as in, a User "likes" a Fantasy rather than "has" it... think of Facebook and how you can "like" a wall-post, even though it doesn't "belong" to you... in fact, the Facebook example is almost exactly what I'm aiming for).
I gathered that I should make another association, but I'm kinda confused as to how I might use it, or if this is even the right approach. I started by adding the following:
class Fantasy < ActiveRecord::Base
...
has_many :users, :through => :approvals
has_many :approvals, :dependent => :destroy
end
class User < ActiveRecord::Base
...
has_many :fantasies, :through => :approvals
has_many :approvals, :dependent => :destroy
end
class Approval < ActiveRecord::Base
belongs_to :user
belongs_to :fantasy
end
... but how do I create the association through Approval rather than through Fantasizing?
If someone could set me straight on this, I'd be much obliged!
Keep your first set of code, then in your User Model add:
has_many :approved_fantasies, :through => :fantasizings, :source => :fantasy, :conditions => "fantasizings.is_approved = 1"
In your Fantasizing table, add an is_approved boolean field.