many to many relationship in rails 3 - ruby-on-rails

I have created 2 models in rails and modified the models classes to add a many to many relationship (with has_and_belongs_to_many)
class User < ActiveRecord::Base
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :users
end
When I create a User though the web interface, I am not asked to select some categories.
Did I miss somthing ? I read that another table was required but it semmed it was in the case of has_many and not has_and_belongs_to_many statement).
Could you please help ?
I think this is a newby question but...
Thanks a lot,
Regards,
Luc

For HABTM you need a join table called categories_users. Use this migration:
def self.up
create_table :categories_users, :id => false do |t|
t.integer :category_id
t.integer :user_id
end
end

What does your view look like? Rails's scaffolding won't account for many-to-many, so you will need to handle it yourself.
What does your data store look like? If you are using a RDBMS, then for many to many relations you typically need a junction table. Many-to-many is not naturally handled by most (all?) SQL databases.

Related

What is the process of creating a joining table which resolves a many-to-many relationship using migrations?

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.

How to setup self-referential polymorphic relationship in rails?

I have a 3 models
User
Journal
Post
A couple of things can be assumed about these
User has_many :journals
Journal has_many :posts
I would like users to be able to subscribe to other users and specific journals on my site.
I am thinking I need a Polymorphic Subscription model that looks something like this
class CreateSubscriptions < ActiveRecord::Migration
def change
create_table :subscriptions do |t|
t.integer :user_id
t.references :subscribable, :polymorphic=>true
t.timestamps
end
end
end
But here's where I'm stuck. I don't know how to setup the polymorphic relationships in my User model.
I want to be able to get the following things:
#user.watched_users
#user.watched_journals
#user.followers
#journal.followers
Can someone help? The docs are kind sparse on this and I know these can be a real chore to setup.
^_^
While I understand the desire to want to just have the user subscribe to arbitrary objects, in practice, you'll end up dealing with these different subscriptions differently, so at least for now (until you find yourself wanting to subscribe to other objects on the site), just leave them separate (YAGNI).
You can do this through a simple join table for each relationship. the answer on How do I do reflexive self-join relationships in ActiveRecord? leads to a good example in http://railscasts.com/episodes/163-self-referential-association

ActiveRecords [something] belongs_to [User] and has_many [Users]

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

Associate one model to two different models?

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

Ruby on Rails: Finding all topics in a certain category?

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.

Resources