If I have a HABTM join table called, :inventory_items_shopping_lists, how do I create and call records in this table? I do not have a join model. The two joined models are :inventory_items and :shopping_lists. I'd like to be able to have a user add :inventory_items to their :shopping_lists. Thanks in advance!
EDIT
Here are the relevant models and my goal:
class InventoryItem < ActiveRecord::Base
belongs_to :item, :foreign_key => :item_id
belongs_to :vendor
has_many :list_items
end
class ListItem < ActiveRecord::Base
belongs_to :inventory_item, :foreign_key => :item_id
belongs_to :shopping_list
end
class ShoppingList < ActiveRecord::Base
has_many :list_items
belongs_to :user, :foreign_key => :user_id
end
I'm attempting to have a :user add :inventory_items to a :shopping_list where they will become :list_items. list_items have almost identical attributes of :inventory_items, so I will likely just reference those attributes through association than by duplicating the attributes in the :list_items table. Thoughts or suggestions on this? I'm newish to RoR so I appreciate any feedback on any part of this plan. Thanks!
how do I create and call records in this table?
You basically don't with a HABTM association type. If you want to store more state on the join table than you will need to use a standard has_many (and maybe a has_many :through) so you can manipulate the underlying join model.
For this reason I have never been a fan of HABTM and in fact I have a handful of large Rails apps in production and I have never used HABTM myself.
Related
i'm building a RoR app
this is my original scenario:
2 models, Clienti and Interventi
class Clienti < ActiveRecord::Base
has_many :interventi, :dependent => :destroy, :foreign_key => "cliente_id"
......
end
class Interventi < ActiveRecord::Base
belongs_to :clienti, :foreign_key => "cliente_id"
.........
end
this is a simple one-to-many relation, each "clienti" has many "interventis" (iterventi is a kind of job in my app).
Today i need to convert this relation from one-to-many to many-to-many, each "interventi" need to have more then one "clienti", so i think i have to change the "cliente_id" column in DB from int to text and store an array of "Clienti's ids" (is it the good way? )
My question is: if it's the good way, how can i keep the association in model so i can still use something like "Clienti.Interventi.count" ?
Thanks to all!
You would need a join model to do this kind of many-to-many association. By convention, you could call it clienti_interventi
class Clienti
has_many :clienti_interventis
has_many :interventis, through: :clienti_interventis
end
class Interventi
has_many :clienti_interventis
has_many :clientis, through: :clienti_interventis
end
class ClientiInterventi
belongs_to :clienti
belongs_to :interventi
end
With this setup, you can keep doing whatever you were doing, as well as Clienti.first.interventis.count or Interventi.first.clientis.count
I would like to create a double entry table form according two models.
For now I'm able to create a simple table with the members of a communities
on the columns, I must add the informations of an other model, like this :
My models :
Community
has_many :memberships
Membership
belongs_to :user
belongs_to :community
User
has_many ::memberships
has_many :skills
Skill
belongs_to :user
belongs_to :community
I there some gem existing to make a double entry table or is it easier to make it from scratch? if so, how can I begin ?
It seems like you would benefit from a through relationship here.
Instead of referencing community directly from the skill table, you could do:
Skill
belongs_to :user
has_many :communities, :through => :user
On user, add:
has_many :communities, :through => :memberships
Wouldn't this get the link between skill and community that you would like?
As Jay mentioned, you would benefit from a has_many :through relationship, or maybe a has_and_belongs_to_many relationship; whether it's the actual solution we'll have to see:
#app/models/user.rb
Class user < ActiveRecord::Base
has_many :memberships
has_many :skill_users
has_many :skills, through: :skill_users
end
#app/models/skill_user.rb
Class SkillUser < ActiveRecord::Base
belongs_to :skill
belongs_to :user
end
#app/models/skill.rb
Class Skill < ActiveRecord::Base
has_many :skill_users
has_many :users, through: :skill_users
end
This will allow you to associate each user (note that members are different than users) with specific skills without using double-entries in your tables
Relational
The basis of what you're seeking can be found in Relational Databases
These work by storing data in single instances, and linking to other data through foreign_keys. These foreign keys are things such as user_id etc:
(more information here)
This means instead of populating the same data twice, it is correct to reference that data from other models, as required. This is where join models come in
Join Model
Join models allow you to "link" two pieces of data through a join model:
For you, it means storing your skills in its own model, and linking users with skills on a join model (I've called skill_user.rb). This means that you'll be able to call your user's skills like this:
#user.skills #-> goes through the join model
I'm new to Rails and have some doubts about the kind of relationship do I need to use. Here is the case.
I have two models Offer and User, a user could belong to to many offers and offers can have many user. Also the users create the offers.
I think I have to use a has_many :through ralationship. For example I've created another model "Applicant". Applicant belongs_to user and belongs_to offer. But how is the relationship from the user and offer model? For example:
User Model
has_many :offer, :through => :applicant
Offer Model
has_many :user, :through => :applicant
My doubt is because I already have this two relationship
User Model
has_many :offers, :dependent => :destroy
Offer Model
belongs_to :user
After solve this, I guest I have to save the record in the applicant model from the applicanst_controller, right?
Thanks in advance
What you have described is a many-to-many relationship using a join table. You're actually pretty close but you just need to remove the has_many :offers, :dependent => :destroy from your user model and the blongs_to :user in your offer model. It should look something like this:
class User < ActiveRecord::Base
has_many :offers, :through => :applicants
end
class Applicant < ActiveRecord::Base
belongs_to :users
belongs_to :offers
end
class Offer < ActiveRecord::Base
has_many :users, :through => :applicants
end
You don't have to worry about the dependent destroy part as associations are automatically removed as the corresponding objects are removed. With a many to many association it doesn't really matter how you go about building the relationship. Either of the following will work:
#user.offers << #offer
#offers.users << #user
If you don't need to store any information specific to your applicant join table (e.g., time stamps, descriptions) you might instead want to look at a has_and_belongs_to_many relationship. Check out choosing between has_many_through and has_and_belongs_to_many for reference.
Edit
Heres the code for a HABTM relationship:
class User < ActiveRecord::Base
has_and_belongs_to_many :offers
end
class Offer < ActiveRecord::Base
has_and_belongs_to_many :users
end
I am trying to create an association between two tables. A student table and a computer table.
A computer can only ever be assigned to one student (at any one time) but a student can be assigned to multiple computers.
This is what I currently have in mind. Setting up a has-many through relationship and modifying it a bit.
class Student < ActiveRecord::Base
has_many :assignemnts
has_many :computers, :through => :assignments
end
class Computer < ActiveRecord::Base
has_one :assignment
has_one :student, :through => :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :student
belongs_to :computer
end
Does this seem like the best way to handle this problem? Or something better sound out quickly to the experts here. Thanks!
You need first to decide if a simple one-to many relationship is enough for you.
If yes, it gets a lot easier, because you can get rid of the Assignment-class and table.
Your database-table "computers" then needs a student_id column, with a non-unique index
Your models should look like this:
class Computer < ActiveRecord::Base
belongs_to :student
end
class Student < ActiveRecord::Base
has_many :computers, :dependent => :nullify
end
"dependent nullify" because you don't want to delete a computer when a student is deleted, but instead mark it as free.
Each of your computers can only be assigned to a single student, but you can reassign it to a different student, for example in the next year.
Actually your approach is fine, as one offered by #alexkv. It is more discussion, than question.
Another thing if you want to use mapping table for some other purposes, like storing additional fields - then your approach is the best thing. In has_many :through table for the join model has a primary key and can contain attributes just like any other model.
From api.rubyonrails.org:
Choosing which way to build a many-to-many relationship is not always
simple. If you need to work with the relationship model as its own
entity, use has_many :through. Use has_and_belongs_to_many when
working with legacy schemas or when you never work directly with the
relationship itself.
I can advise you read this, to understand what approach better to choose in your situation:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off
You can also use has_and_belongs_to_many method. In your case it will be:
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers, :join_table => 'assignments',
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student, :join_table => 'assignments',
end
or you can rename assignments table to computers_students and remove join_table
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student
end
I have a User model, Person model and Company model.
a User has many companies through Person and vice versa.
But i would like to be able to populate People and Companies that are not tied to Users that can be tied later.
class User < ActiveRecord::Base
attr_accessible :name
has_many :people
has_many :companies, :through => :people
end
class Person < ActiveRecord::Base
attr_accessible :user_id, :company_id
belongs_to :users
belongs_to :companies
end
class Company < ActiveRecord::Base
attr_accessible :name
has_many :people
has_many :users, :through => :person
end
now in the console i want to be doing the following
User.find(1).companies
then it should find me the companies in which user(1) is a person of interest.
Have I got this wrong, is there a small change that I should be making.
Your Person model can't directly "belong_to" more than one, your belongs_to :users and belongs_to :companies associations won't work that way. Companies-to-people need to be connected through another join table that describes the relationship between them, for example Employment which points to one instance of each model:
class Person < ActiveRecord::Base
has_many :employments
has_many :companies, :through => :employments
end
class Employment < ActiveRecord::Base
belongs_to :person
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :employments
has_many :people, :through => :employments
end
You can then use the :through option to associate the many companies/people on the other side of that employment relationship in the middle.
Similarly, if a Person can be owned by more than one User then you will need a join model between those two entities as well.
Just as a followup, in a has_many :through relationship, there is nothing that says you cannot use your join table (in your case, Person) independently. By nature of the relationship, you are joining through a completely separate ActiveRecord model, which is what most notably distinguishes it from the has_and_belongs_to_many relationship.
As Brad pointed out in his comment, you need to pluralize 'person' to 'people' in your relationship. Other than that, it looks like you set it up correctly. Exposing :user_id and :company_id with attr_accessible will enable you to mass-assign these values later from a postback, but often times you want to shy away from doing so with role-based associations, as you may not want to leave them exposed to potential HTTP Post attacks.
Remember, in your controller you can always do something like this with or without attr_accessible:
#person = Person.new
#person.user = User.find(...)
#person.company = Company.find(...)
#person.save
Hope that helps.