Like ownership.
Suppose I already have two models:
person name:string
dog name:string
Now I need to have the third table - ownership.
In a normal relational database, I only need to store the two ids from those tables, but rails automatically generates them. So how can I reference them?
rails generate model Ownership XXXXXXXX
You can set up a relationship model, like this:
rails generate model ownerships person:references dog:references
rails db:migrate
app/models/ownership.rb:
class Ownership < ApplicationRecord
belongs_to :person
belongs_to :dog
end
app/models/person.rb:
class Person < ApplicationRecord
has_many :ownerships
has_many :dogs, through: :ownerships
end
Now you can do:
john = Person.create(name: 'John')
doggy = Dog.create(name: 'Doggy')
john.dogs << doggy
And you just added a dog to John's ownerships. You can find them like this:
puts john.dogs.first.name
# => "Doggy"
If you look at your generated schema.rb:
create_table "ownerships", force: :cascade do |t|
t.integer "person_id" # Here are your two ids
t.integer "dog_id" #
# ...
I would recommend you going through Rails Tutorial by Michael Hartl. In the last section he implements a relationship model with very thorough explanation.
What you want is a has_ :through relationship or a has_and_belongs_to_many relationship. Check the docs for more info (you can find detailed explanation on how to set up the DB and relationship.)It is a standard issue in rails:
http://guides.rubyonrails.org/association_basics.html
Related
I am building a rails exercise app that has both exercises and routines. I want each routine to be composed of several exercises (has_many :exercises), but an exercise doesn't necessarily have to belong to a routine. Is there a way to do that?
Reading the guides is always a good start. This works from Rails 5 onwards.
belongs_to :routine, optional: true
You probably want a many-to-many relationship here, rather than a one-to-many relationship.
It would seem you would want for an Exercise to be associated with any number of Routines, and for a Routine to be associated with one or more Exercises.
You end up with something like this:
# app/models/routine.rb
class Routine < ActiveRecord::Base
has_and_belongs_to_many :exercises
end
# app/models/exercise.rb
class Exercise < ActiveRecord::Base
has_and_belongs_to_many :routines
end
# db/migrate/1213123123123_create_exercises_routines_join_table.rb
class CreateExercisesRoutinesJoinTable < ActiveRecord::Migration
def self.change
create_table :exercises_routines, :id => false do |t|
t.integer :exercise_id
t.integer :routine_id
t.index [:category_id, :routine_id]
end
end
end
I would like to create a structure of Users having many friends, also of class User:
class User < ActiveRecord::Base
has_and_belongs_to_many :friends, class_name: "User"
end
I do not need any details of their relationship thus I do not use :through with kind of class Friendship. But now I cannot find any way how to create corresponding database (neither with migration file nor using rails g model User username:string ... command). Any ideas?
Here are some resources which may be helpful:
RailsCasts episode #163 Self-Referential Association regarding self-referential many-to-many relationships
RailsCasts episode #47 Two Many-to-Many. This might be more relevant to what you're attempting to accomplish
A gist someone created for self-referential relationships using HABTM
I'll summarize the information found in those links:
Given that you're describing a self-referential many-to-many relationship, you will of course end up with a join table. Normally, the join table should be deliberately named in such a way that Rails will automatically figure out which models the table is joining, however the "self-referential" part makes this a tad awkward, but not difficult. You'll merely have to specify the name of the join table, as well as the joining columns.
You'll need to create this table using a migration that will probably look something like this:
class CreateFriendships < ActiveRecord::Migration
def self.up
create_table :friendships, id: false do |t|
t.integer :user_id
t.integer :friend_user_id
end
add_index(:friendships, [:user_id, :friend_user_id], :unique => true)
add_index(:friendships, [:friend_user_id, :user_id], :unique => true)
end
def self.down
remove_index(:friendships, [:friend_user_id, :user_id])
remove_index(:friendships, [:user_id, :friend_user_id])
drop_table :friendships
end
end
I'm not certain whether there is a shortcut way of creating this table, but bare minimum you can simply do rails g migration create_friendships, and fill in the self.up and self.down methods.
And then finally in your user model, you simply add the name of the join table, like so:
class User < ActiveRecord::Base
has_and_belongs_to_many :friends,
class_name: "User",
join_table: :friendships,
foreign_key: :user_id,
association_foreign_key: :friend_user_id
end
As you can see, while you do have a join table in the database, there is no related join model.
Please let me know whether this works for you.
In the below example, do I have to create employee_id in the Office model, or is it created automatically by db:migrate?
class Employee < ActiveRecord::Base
has_one :office
end
class Office < ActiveRecord::Base
belongs_to :employee # foreign key - employee_id
end
Feels like I'm missing something fundamental. I'm trying to get a basic one to many relationship working, where I can use a drop-down select of objects from the one side. Are there any good basic tuts explaining how this works?
I had to create _ids in all the models where I wanted this to work, but it doesn't seem right from examples I've looked at.
two steps.
firstly, you have to create an employee_id field in the office table in the migration file. you will have something like that :
class CreateOffices < ActiveRecord::Migration
def change
create_table :offices do |t|
t.string :name
t.integer :employee_id
t.timestamps
end
end
end
secondly, you have to define the association in the model. by convention, if you name the foreign_key field employee_id, you don't have to specify the name of it in the model.
class Office < ActiveRecord::Base
belongs_to :employee
end
should be enough.
Associations in ActiveRecord comprise two parts. Hooking together the model objects (like you've done) and setting up the database. So you'll need to define the association in your migration like so:
def change
create_table :offices do |t|
# Other migrations
t.references :employee
end
end
Alternatively you can do t.integer :employee_id which will achieve the same end too.
I'm interested in creating and updating a row in table without a primary key. My table has 3 columns - person_id, year and salary. I understand that I should use has_and_belongs_to but I'm having problems understanding how to implement my create and update methods and my form.html file. Can anyone help explain this to me, perhaps with a simple example of how to do it?
has_and_belongs_to_many example
# category model
class Category < ActiveRecord::Base
has_and_belongs_to_many :users
end
# user model
class User < ACtiveRecord::Base
has_and_belongs_to_many :categories
end
join table look like
class CreateCategoriesUsersJoinTable < ACtiveRecord::Migration
def change
create_table :categories_users, :id => false do |t|
t.integer :category_id
t.integer :user_id
end
end
end
now you can accessing your information
$ User.categories
$ Category.users
$ user = User.first
$ user.categories
$ category = Category.first
$ category.users
Add a primary key, and ignore it. You can add a unique index on (person_id, year) to simulate a PK constraint, but ActiveRecord heavily relies on having ids for its instances.
I have two models Group and Person that I want to have a many-to-many relationship, but I'm unclear on how to manage the relationship itself. I want to be able to create groups and persons separately -- NOT necessarily via a nested model -- and then link persons to groups from the group view/model itself.
Does anyone have any suggestions on how to do so?
I thought of creating a many-to-many relationship via a join model and then accepting nested attributes for the join model in the Group model -- so I believe I will be able to add and remove relationships via the Group view/model. Does this approach make sense?
I would create a PersonGroup model that looks like this:
class PersonGroup < ActiveRecord::Base
has_many :people
has_many :groups
end
And you might also do rails generate migration create_person_group and put this in the up method of the generated migration file:
create_table :person_group do |t|
t.integer :person_id, :null => false
t.integer :group_id, :null => false
t.timestamps
end
add_index :person_group, [:person_id, :group_id], :unique => true
Then in Person:
class Person < ActiveRecord::Base
has_many :person_groups
has_many :groups, :through => :person_groups
end
And in Group:
class Group < ActiveRecord::Base
has_many :person_groups
has_many :people, :through => :person_groups
end
Create a junction table. Junction tables are used when you want to store many-to-many relationships. I don't develop in ROR so I don't know the specifics for ActiveRecord but I am sure that this can help you think about the problem as well.
group_id INTEGER,
person_id INTEGER