I want to create lists that are edited by many users. So I go with many to many relations like this.
class User < ActiveRecord::Base
has_many :editabilities, :dependent => :destroy
has_many :editable_lists, :through => :editabilities, :source => :list
end
class List < ActiveRecord::Base
has_many :editabilities, :dependent => :destroy
has_many :editors, :through => :editabilities, :source => :user
end
class Editability < ActiveRecord::Base
belongs_to :list
belongs_to :user
end
And I add a editor for a list by like this.
u = User.first
l = List.first
Editability.create(user_id: u.id, list_id: l.id)
It seems to be working. But I'm not sure whether I am doing in a right way or wrong way. Is this a right way to do?
Also:
u = User.first
l = List.first
u.editable_lists << l
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
Related
Let's say we have a User.
A user has_many documents through account like so…
class User < ActiveRecord::Base
belongs_to :account
has_many :documents, :through => :account, :order => "created_at DESC"
end
class Account < ActiveRecord::Base
has_one :owner, :class_name => "User", :dependent => :destroy
has_many :documents, :dependent => :destroy
end
class Document < ActiveRecord::Base
belongs_to :account
end
Nice and simple, this is where it gets tricky…
A user can also collaborate on documents, this via the collaborators join table…
class Collaborator < ActiveRecord::Base
belongs_to :user
belongs_to :documnet
end
class Document < ActiveRecord::Base
has_many :collaborators, :dependent => :destroy
has_many :users, :through => :collaborators
accepts_nested_attributes_for :collaborators, :allow_destroy => true
end
The final user bit of this is what i'm not sure about. I want to add another has many documents, and when you call user.documents it blends both documents via their account and the ones they're collaborating on…
class User < ActiveRecord::Base
belongs_to :account
has_many :documents, :through => :account, :order => "created_at DESC"
#documents need to do both has manys…
has_many :collaborators, :dependent => :destroy
has_many :documents, :through => :collaborators
end
Thanks, it's a bit long but I can think of a neat solution. Any help would be much appreciated.
You can create a method that will request on the tables documents, accounts and collaborators to find the documents related to the user:
class User < ActiveRecord::Base
#...
def documents
Document.includes(:account, :collaborators).where('collaborators.user_id = ? OR documents.account_id = ?', self.id, self.account.id)
end
end
I've not tested this request, but I hope you get the idea. Please correct it if it's erroneous.
For the 2 has_many documents, :through..., you can remove them if you don't need them anymore; Otherwise, you have to give them different names (and different from the method above).
I have 3 models: User, Object, Likes
Currently, I have the model: a user has many Objects. How do I go about modeling:
1) A user can like many objects
2) an Object can have many likes (from different users)
So I want to be able to do something like this:
User.likes = list of objects liked by a user
Objects.liked_by = list of Users liked by object
The model below is definitely wrong...
class User < ActiveRecord::Base
has_many :objects
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
belongs_to :users
has_many :users, :through => :likes
end
To elaborate further on my comment to Brandon Tilley's answer, I would suggest the following:
class User < ActiveRecord::Base
# your original association
has_many :things
# the like associations
has_many :likes
has_many :liked_things, :through => :likes, :source => :thing
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :thing
end
class Thing < ActiveRecord::Base
# your original association
belongs_to :user
# the like associations
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
end
You are close; to use a :through, relation, you first must set up the relationship you're going through:
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Likes < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Objects < ActiveRecord::Base
has_many :likes
has_many :users, :through => :likes
end
Note that Objects should has_many :likes, so that the foreign key is in the right place. (Also, you should probably use the singular form Like and Object for your models.)
Here is a simple method to achieve this. Basically, you can create as many relationships as needed as long as you specify the proper class name using the :class_name option. However, it is not always a good idea, so make sure only one is used during any given request, to avoid additional queries.
class User < ActiveRecord::Base
has_many :likes, :include => :obj
has_many :objs
has_many :liked, :through => :likes, :class_name => 'Obj'
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :obj
end
class Obj < ActiveRecord::Base
belongs_to :user
has_many :likes, :include => :user
has_many :users, :through => :likes
# having both belongs to and has many for users may be confusing
# so it's better to use a different name
has_many :liked_by, :through => :likes, :class_name => 'User'
end
u = User.find(1)
u.objs # all objects created by u
u.liked # all objects liked by u
u.likes # all likes
u.likes.collect(&:obj) # all objects liked by u
o = Obj.find(1)
o.user # creator
o.users # users who liked o
o.liked_by # users who liked o. same as o.users
o.likes # all likes for o
o.likes.collect(&:user)
Models & associations as per naming conventions of rails modeling
class User < ActiveRecord::Base
has_many :likes
has_many :objects, :through => :likes
end
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Object < ActiveRecord::Base
belongs_to :user
has_many :likes
has_many :users, :through => :likes
end
Also, you can use of already built-in gems like acts-as-taggable-on to have same functionality without code :)
I have 3 models(Allen, Bob, Chris) which are polymorphic with Join model. and a User model which connect with the join model.
class Allen < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Bob < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Chris < ActiveRecord::Base
has_many :joins, :as => :resource
...
end
class Join < ActiveRecord::Base
belongs_to :initiator, :class_name => "User", :foreign_key => "user_id"
:counter_cache => "How to write with 3 different counter cache?"
belongs_to :resource, :polymorphic => true, :counter_cache => :resources_count
end
class User < ActiveRecord::Base
has_many :joins
has_many :allens, :through => :joins, :source => :initiator
has_many :initial_joins, :class_name => "Join"
end
My question is how to write the counter cache for Bob, Chris and Allen in User Model
or you can review it here: https://gist.github.com/1350922
I think, there's no standard way to achieve this. Add an after_create callback to your Allen, Bob and Chris where you would get the list of all Users associated with this particular Bob and recalculate bobs_count for each of them manually.
I need to access institution in two ways.
My models are given below:
class Person < ActiveRecord::Base
has_many :institution_people
has_many :institution_choices
has_many :institutions, :through => :institution_people
has_many :institutions, :through => :institution_choices
fields........
end
class Institution < ActiveRecord::Base
has_many :people, :through => :institution_people
has_many :people, :through => :institution_choices
has_many :institution_people
has_many :institution_choices
end
class InstitutionChoice < ActiveRecord::Base
belongs_to :person
belongs_to :institution
end
class InstitutionPerson < ActiveRecord::Base
belongs_to :person
belongs_to :institution
end
The i setup the models like this is that person can study in different institutions, so for this i setup
has_many :institutions, :through => :institution_people
for person model
But at the same time person can have institution choices, so i setup
has_many :institutions, :through => :institution_choices
for person model.
How should i setup model and association between person and institutions so that i can find institutions from person in both ways.
Right now
Person.first.institutions
finds from institution_people table, as
has_many :institutions, :through => :institution_people
is at beginning i guess.
Some other techniques are welcomed so that i can get institutions in both ways.
In your Person model, try this :
class Person < ActiveRecord::Base
has_many :institution_people
has_many :institution_choices
has_many :institutions_people, :through => :institution_people, :source => :institutions, :class_name => "Institution"
has_many :institutions_choices, :through => :institution_choices, :source => :institutions, :class_name => "Institution"
end
http://guides.rubyonrails.org/association_basics.html#has_many-association-reference
Basically, you need some kind of interface here. What i would do:
in institutions model:
scope :institutions_of, proc { |person| joins(' INNER JOIN (' + Person.institution_ids(person) + ') q
ON institutions.id = q.ip_iid OR institutions.id = q.ic_iid').where(['institutions.person_id = ?', person_id]
( it joins the query(scope) from Person.rb below )
in Person.rb :
scope :institution_ids, proc { |person| select('ip.institution_id ip_idd, ic.institution_id ic_idd
from institution_people ip
inner join institution_choice ic on ip.person_id = ic.person_id').
where(['ip.person_id = ?', person.id])
(this should retrieve all institutions ids from both tables)
ugly as hell, but still might work. You could use is then like: Institution.institutions_of(current_user)
If you don't need to keep the result as an ActiveRelation
class Person < ActiveRecord::Base
has_many :institution_people
has_many :institution_choices
def institutions
institution_people + institution_choices
end
end
If you DO need the keep it (in order to call person.institutions.order('name'), by example), then it's more complicated:
class Person < ActiveRecord::Base
has_many :institution_people
has_many :institution_choices
scope :institutions, :select => 'select * from (select * from institution_people union all select * from institution_choices) as institutions'
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.