Hey guys. I'm trying to build this Picture Battle site, (where you chose the picture you prefer) and I had two models. Pictures, and Battles.
So Each Picture has_many Battles, but Each Battle belongs to two pictures. How do I associate it.. I was thinking something like "belongs_to_many" but apparently that doesn't exist.
from what i see this could be easily done by using a has_and_belongs_to_many association
You should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, which is probably the case, it may be simpler to set up a has_and_belongs_to_many relationship
here's how you do the HABTM:
class Picture < ActiveRecord::Base
has_and_belongs_to_many :battles
end
and
class Battle < ActiveRecord::Base
has_and_belongs_to_many :pictures
end
then you can call picture.battles and battle.pictures
you will also need to create a new migration that looks like this
class CreateBattlesPicturesJoinTable < ActiveRecord::Migration
def self.up
create_table :battles_pictures, :id => false do |t|
t.integer :battle_id
t.integer :picture_id
end
end
def self.down
drop_table :battles_pictures
end
end
more info here
It is a many-to-many association. You can achieve it through a join model. Check has_many in the API docs
Related
I would like to understand the process which can be followed to create models and migrations which in turn create a joining table within the database to resolve a many-to-many relationship. For instance. If i have a course table, a students table and i want to create a joining table called studies with the id from course and students along with extra data such as the grade and date started. Exactly What is the process for doing this?
If i am to use the generate model command for each of the above 3 table names, this will create a separate migration for all of them. Even if i go into the models and add the relevant associations this will not affect how the database is created? Please could you give me some guidance on what steps i must take in order to create the required foreign key relationships here with some examples?
Use a has_many :through association. Set it up manually.
Step 1: Generate your models separately. The joining model Study will contain foreign keys, so remember to include the columns.
rails g model Course title:string
rails g model Student name:string
rails g model Study course_id:integer student_id:integer start_date:date grade:string
Step 2: Set up associations:
# models/course.rb
class Course
has_many :studies
has_many :students, through: :studies
end
# models/student.rb
class Student
has_many :studies
has_many :courses, through: :studies
end
# models/study.rb
class Study
belongs_to :course
belongs_to :student
end
Step 3: Run migrations, restart server (if necessary), and that's it. Rails will handle the rest.
Accessing attributes in the joining table may require careful timing to ensure the correct object is being accessed, since the joining object is not returned via Rails' built-in methods, ie #course.students. Check out this answer for some ideas.
Read the guide for more information.
for many-to-many relationships use:
class Car < ActiveRecord::Base
has_and_belongs_to_many :tires
end
class Tire < ActiveRecord::Base
has_and_belongs_to_many :cars
end
Then you create a migration like this:
class CreateCarsAndTires < ActiveRecord::Migration
def change
create_table :cars do |t|
t.string :name
end
create_table :tires do |t|
t.string :something
end
create_table :cars_tires do |t|
t.belongs_to :car
t.belongs_to :tire
t.string :additional_dataA //optional
t.int :something_else //optional
end
end
end
It is very important that you name your join table in the migration in alphabetical order (c in cars comes before t for tires) as ActiveRecord will look in has_many_and_belongs_to relations for a table which is named this way pluralized-classA_pluralized_classB like apples_bananas vs bananas_apples which would not work and you would have to add the table name to your classes and it goes against the convention over configuration paradigm.
Hope it helps.
I plan on making a genotype calculator in the future. I intend for this calculator to eventually be able to compute the following from a pairing: probability of color listing all possibilities, genotype.
I am wanting to make a dropdown menu/text field combination on a very simple webpage to learn how it works so that I can continue my project and hopefully meet this goal. I have searched and tried to figure this out, but I am pretty lost. Currently in my database I have a table called "colors" with the following schema:
id
angora_color
genotype
created_at
updated_at
I do not intend for users to be able to add data to this form. I want them to be able to select a color from the dropdown box, and get the genotype in a text field below it.
My code so far is as follows:
class Color < ActiveRecord::Base
has_one :genotype
end
class Genotype < ActiveRecord::Base
has_one :color
end
index.html.erb:
<h2>Placeholder for Genotype List..</h2>
class PagesController < ApplicationController
def index
end
end
I appreciate any help.
Are you sure you only want a has_one relationship? Wouldn't a Genotype have many colors? and Colors can be part of many Genotypes?
You also can't have both models declare has_one. One model has to belong to the other. And the one that belongs_to should have the foreign key as <model_name>_id e.g. genotype_id. In your table you only put genotype. Rails looks for that _id.
What may be better here is to use has_many through. Create a join model such as genotypes_colors:
rails g model GenotypesColor genotype_id:integer color_id:integer
Then change your code to look like:
class Genotype < ActiveRecord::Base
has_many :genotypes_colors
has_many :colors, through: :genotypes_colors
end
class GenotypesColor < ActiveRecord::Base
belongs_to :genotype
belongs_to :color
end
class Color < ActiveRecord::Base
has_many :genotypes_colors
has_many :genotypes, through: :genotypes_colors
end
Now you can correctly relate a Genotype to its Colors. You can use fields_for in either model's forms to create the genotypes_color association that will relate a Genotype to any Color or vice versa. If this sounds about right let me know and I can further help on how to do the forms.
Right now my migration reads as follows:
class CreateColors < ActiveRecord::Migration
def change
create_table :colors do |t|
t.string :angora_color
t.string :genotype
t.timestamps
end
end
end
Im not sure i understand rails polymorphic.
In Java you can create Objects from the same Objecttype:
http://www.fh-kl.de/~guenter.biehl/lehrgebiete/java2/j2-08-Dateien/abb.8.10.jpg
Person trainer = new Trainer()
Person sportler = new Trainer()
In Rails http://guides.rubyonrails.org/association_basics.html#polymorphic-associations:
In this example: picture can be from an employee or from a product, sounds strange because this is not realy the same type.
Do i understand the real purpose: to save objects in the same container an array of person or image?
In my rails project: I have several person: sportsmen, trainer and guest. They are sons of person (inheritance).
I think i meet the inheritance reason.
There is another class named exercise.
Sportsmen and trainer can create exercises.
So i want to use polymorphic. Exercises can be from trainer or sportsmen. Like in the example of the rails page, images can be from employee or a product.
Do i meet the best practise?
How do i implement a has_many :through with polymorphy?
It is not possible to use a habtm assoziation with polymorphic.
You have to define a additional class, but how exactly?
I think you want single table inheritance (STI) models, not a polymorphic relationship.
See this article http://www.alexreisner.com/code/single-table-inheritance-in-rails and these stackoverflow answers Rails - Single Table Inheritance or not for Applicant/Employee relationship Alternative to Rails Single Table Inheritance (STI)?
Just to make it clear, you should use polymorphic associations when you have a model that may belong to many different models on a single association.
Suppose, you want to be able to write comments for users and stories. You want both models to be commendable. Here's how this could be declared:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :comment, as: :commentable
end
class Product < ApplicationRecord
has_many :comment, as: :commentable
end
To declare the polymorphic interface (commendable) you need to declare both a foreign key column and a type column in the model.
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.integer :commentable_id
t.string :commentable_type
t.timestamps
end
add_index :comments, :commentable_id
end
end
You can check more details about associations here.
I'm modelling a scenario with Users and Tools, where a Tool is owned by one User but can be used by many Users including to one owning it.
I was thinking about adding an owner_id column to Tools and say it has_many Users or by adding a new relationsship table.
I'm really new to Rails and I have problems setting up the right associations in the models though, maybe you can point me in the right direction?
Thank you very much.
Your should add owner_id to the Tools table.
Associations will be like that.
class User < ActiveRecord::Base
has_and_belongs_to_many :tools
end
class Tool < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :owner, :class_name => 'User'
end
You'll need a tools_users table in order to use habtm-association. Generate a migration and create a table with option id: false and two columns user_id and tool_id:
class CreateToolsUsersTable < ActiveRecordMigration
def change
create_table :tools_users, id: false do |t|
t.integer :tool_id
t.integer :user_id
end
end
end
After that you can call something like #user.tools or #user.owner
Read more there
User has many tools
Tool belongs to user in owner
Tool has many users
is what I would do.
I'm not sure about the wording because I don't use Active Record but this is how it works in other orms
I'm trying to find all topics in a one particular category, but I'm not sure if this is the most efficient way to do it:
Topic.all.select { |topic| topic.categories.include?(category) }
The above works for me but it seems that it takes MySQL a long time to find the records. Is there anything more efficient?
It sounds like right now you have a has_many relationship between topics and categories, when you need a many-to-many relationship. Restructure your models like this:
# app/models/category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :topics
end
# app/models/topic.rb
class Topic < ActiveRecord::Base
has_and_belongs_to_many :categories
end
Then create a join table without a primary key. Create the new migration like so:
script/generate migration AddCategoriesTopicsJoinTable
And add these contents:
class AddCategoriesTopicsJoinTable < ActiveRecord::Migration
def self.up
create_table :categories_topics, :id => false do |t|
t.integer :category_id
t.integer :topic_id
end
end
def self.down
drop_table :categories_topics
end
end
Notice the join table is named by combining the two table names, in alphabetical order. That's how Rails will know how to find it automatically.
Now you can call #category.topics and get an array of the topics, and you can call #topic.categories and get the categories. It works in both directions.
UPDATE: questions about many-to-many relationships in Rails have come up often enough that I wrote an article called basic many-to-many associations to explain how to use habtm vs has_many :through, and the differences between them.