Rails adding many to many association? - ruby-on-rails

i have a "Question" model and a "Tag" model. I added a many-to-many association to these two model.
that's what i have now :
class Question < ActiveRecord::Base
attr_accessible :content, :score, :title
has_and_belongs_to_many :tags
end
class Tag < ActiveRecord::Base
attr_accessible :description, :name
has_and_belongs_to_many :questions
end
What should i do to update the database and the controllers ?
thanks

Create a migration for the join table with the following command:
$ rails g migration questions_tags question_id:integer tag_id:integer
Create the table in the database:
$ rake db:migrate
Rails magic will help you populate the join table. I created a many-to-many code quiz with a has_and_belongs_to_many example that you might find helpful.

You can consult with Rails Guide on associations here. Here's a code snippet right from there:
# Models
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
# Corresponding migration for creating models and join table
class CreateAssembliesAndParts < ActiveRecord::Migration
def change
create_table :assemblies do |t|
t.string :name
t.timestamps
end
create_table :parts do |t|
t.string :part_number
t.timestamps
end
create_table :assemblies_parts do |t|
t.belongs_to :assembly
t.belongs_to :part
end
end
end

Related

How add association with custom FK in Ruby on Rails?

I have two models: Users and Microposts. There is an association between one-to-many. I would like to add to Microposts field replic_to and replics_from to Users, and association with many-to-many relationships that will not only be stored in the model Microposts the author, but the user ID, which is addressed to the message. Because of already having associations between models, I think you need to specify the force field as FK for new association. I ask you to show how it can be done. Thank you in advance.
This`s sources:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
class CreateMicroposts < ActiveRecord::Migration
def change
create_table :microposts do |t|
t.string :content
t.integer :user_id
t.timestamps
end
add_index(:microposts, [:user_id, :created_at]);
end
end
class User < ActiveRecord::Base
....
has_many(:microposts, dependent: :destroy);
....
end
class Micropost < ActiveRecord::Base
....
belongs_to :user;
....
end
Add to micropost.rb
belongs_to :replics_to, class_name: 'User'
The corresponding field should be
add_column :microposts, :replics_to_id, :integer
For user.rb
has_many :replics_from, class_name: 'User', foreign_key: 'replics_to_id'

Model with unknown number of an attribute

Ruby on Rails 4
I want to create a Model "Test" that can have anywhere from 2 to 200 questions. There will be many tests. Each test will have different variations of questions.
I was thinking of making an attribute called "questions_ids". I would have to make a string that delimited question_ids by commas.
Or I could make the Model with 200 question_id attributes. This would make the question_id(s) easier and faster to retrieve.
Is there another way? Which is preferred? What if I have 1,000 questions? Thank you
models/test.rb
class Test < ActiveRecord::Base
has_many :test_questions
end
models/test_question.rb
class TestQuestion < ActiveRecord::Base
belongs_to :question
belongs_to :test
end
models/question.rb
class Question < ActiveRecord::Base
has_many :tests
end
db/migrate/initial_migration.rb
class InitialMigration < ActiveRecord::Migration
def self.up
create_table :tests do |t|
t.string :name
end
create_table :test_questions do |t|
t.references :table
t.references :question
end
create_table :questions do |t|
t.string :name
end
end
This will also create appropriate indexes.

has_one relationship is resulting in ActiveModel::MissingAttributeError , what am I missing here?

I feel like I am overlooking something obvious here. I can create a story model, and a category model, but I can't relate a story to a category.
Here is how I reproduce the error:
s = Story.new(title: "test", picture_url: "www.google.com")
c = Category.last
s.category = c
error: ActiveModel::MissingAttributeError: can't write unknown attribute `story_id'
Story model
class Story < ActiveRecord::Base
has_many :chapters, dependent: :destroy
has_many :users, through: :story_roles
has_one :category
end
Story migration file
class CreateStories < ActiveRecord::Migration
def change
create_table :stories do |t|
t.string :title
t.string :picture_url
t.integer :category_id
t.timestamps
end
end
end
Category model
class Category < ActiveRecord::Base
belongs_to :story
validates_presence_of :body
end
Category migration
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :body
t.timestamps
end
end
end
In your story model, change has_one :category to belongs_to :category. A rule of thumb is if you have a foreign key for a model, you declare the association as belongs_to. In this example, you have category_id in the story model so you use belongs_to :category in the story model. This makes perfect sense since a story should really belong to a category and a category has_many stories.
You miss t.references :story in your migration. The belongs_to method on category requires story_id.
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.references :story
t.string :body
t.timestamps
end
end
end
You are missing a foreign_key story_id in your Category Model. Add that column in your categories table and migrate it.That would resolve your issue.
Note: Before migrating the changes,roll back the previous migration.
OR
The best way is what #bekicot suggested. Just add t.references :story. This includes story_id,so that it will be added to your categories table by default.

Creating a database relationship that allows for multiple assignments of the same id

I'm really new to RoR so I apologize if I'm not thinking about this right. I have a Report where I need to be able to assign multiple users to that report. A user can be assigned to more than one report and a report can have multiple users. How do I create the database relationship where this would be allowed. I understand how to assign one user to one report but not many users to a single report.
I'd use a joining class to make this happen:
class Report
has_many :assignments
has_many :users :through => :assignments
end
class User
has_many :assignments
has_many :reports, :through => :assignments
end
class Assignment
belongs_to :report
belongs_to :user
end
The class Assignment has two fields: report_id and user_id to create the relationship.
Read the Ruby on Rails Guide to Active Record Associations: http://guides.rubyonrails.org/association_basics.html
I highly recommend you familiarize yourself with the Ruby on Rails guides. They will prove to be an invaluable asset!! For this task the site would be RailsGuides Active Record Associations.
As far as the code goes you want to create three database tables: reports, reports_users, and users, with reports_users being a join table.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class ReportsUsers < ActiveRecord::Migration
def change
create_table :reports_users, :id => false do |t|
t.references :user, :null => false
t.references :report, :null => false
end
end
end
Once you run this migration you need to set up the active record associations in your models.
class User < ActiveRecord::Base
has_and_belongs_to_many :reports
end
class Report < ActiveRecord::Base
has_and_belongs_to_many :user
end
This will set up the database and the many-to-many models connections. This will get you started. Now you have to go create some views

rails model has_many :through associations

I am trying to get my relationships worked out but I am having trouble using the associations.
So I have three models Workout, Exercise and WorkoutExercise. A workout should have many exercises and a exercise should have different workouts therefore I wrote:
class Workout < ActiveRecord::Base
has_many :workout_exercises
has_many :exercises, :through => :workout_exercises
end
class Exercise < ActiveRecord::Base
has_many :workout_exercises
has_many :workouts, :through => :workout_exercises
end
class WorkoutExercise < ActiveRecord::Base
belongs_to :exercise
belongs_to :workout
end
I am running some tests but the tests aren't passing once I create a workout, exercise and then join them in the workout_exercise class. It won't let me access the exercises in the workout like this:
Workout.create
Exercise.create
WorkoutExercise.create(:workout => Workout.first, :exercise => Exercise.first)
work = Workout.first
work.exercises.count #This line causes the error: undefined method exercises
My database tables look like this:
class CreateWorkouts < ActiveRecord::Migration
def change
create_table :workouts do |t|
t.string :title
t.text :description
t.float :score
t.timestamps
end
end
end
class CreateExercises < ActiveRecord::Migration
def change
create_table :exercises do |t|
t.string :title
t.text :description
t.float :value
t.timestamps
end
end
end
class CreateWorkoutExercises < ActiveRecord::Migration
def change
create_table :workout_exercises do |t|
t.timestamps
end
end
end
When I run this tests it says exercises is undefined. Does anyone have any ideas?
Ok, so your WorkoutExercises table can't be empty. This is how it should look:
class CreateWorkoutExercises < ActiveRecord::Migration
def change
create_table :WorkoutExercises do |t|
t.integer :exercise_id, :null => false
t.integer :workout_id, :null => false
t.timestamps
end
# I only added theses indexes so theoretically your database queries are faster.
# If you don't plan on having many records, you can leave these 2 lines out.
add_index :WorkoutExercises, :exercise_id
add_index :WorkoutExercises, :workout_id
end
end
Also, you can name this table whatever you'd like, it doesn't have to be WorkoutExercises.
However, if you were using a has_and_belongs_to_many relationship, your table would have to mandatorily be named ExercisesWorkout. Notice how Exercises comes before Workout. The names have to be alphabetically ordered. Don't ask me why, it's just a Rails convention.
So, in this case, you'll do fine with your table being named WorkoutExercises. But if I were you, I'd change it to ExercisesWorkout, just in case, so that you never get it wrong.
Your code looks OK. Bug maybe has_and_belongs_to_many is a better choice. See Choosing Between has_many :through and has_and_belongs_to_many

Resources