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.
Related
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'
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.
Very new to Rails, have managed a few simple projects, but now stepping into more complex associations between tables and was hoping for some help.
The scenario can best be related to a sports match. Let's say we have
1) A Team (has_many players)
2) A Player (belongs_to team)
3) A Match -- now it gets tricky.
A Match will have: 2 teams, and 22 players (11 on each side) that take part in it. Also, associated with each player, will be their scores for the match (for example, Shots on goal, Goals scored, Points, etc.)
What would be the best practice to create this kind of association? Any tips would be greatly appreciated.
Models
app/models/team.rb
class Team < ActiveRecord::Base
has_many :players, inverse_of: :team
has_many :team_matches
has_many :matches, through: :team_matches
end
app/models/player.rb
class Player < ActiveRecord::Base
belongs_to :team, inverse_of: :player
has_many :player_matches
has_many :matches, through: :player_matches
end
app/models/match.rb
class Match < ActiveRecord::Base
has_many :players, through: :player_matches
has_many :teams, through: :team_matches
end
app/models/team_match.rb
class TeamMatch < ActiveRecord::Base
belongs_to :team
belongs_to :match
end
app/models/player_match.rb
class PlayerMatch < ActiveRecord::Base
belongs_to :player
belongs_to :match
end
Migrations
db/migrate/create_matches.rb
class CreateMatches < ActiveRecord::Migration
def change
create_table :matches do |t|
t.datetime :happened_at
t.timestamps
end
end
end
db/migrate/create_players.rb
class CreatePlayers < ActiveRecord::Migration
def change
create_table :players do |t|
t.string :name
t.timestamps
end
end
end
db/migrate/create_teams.rb
class CreateTeams < ActiveRecord::Migration
def change
create_table :teams do |t|
t.string :name
t.timestamps
end
end
end
db/migrate/create_player_matches.rb
class CreatePlayerMatches < ActiveRecord::Migration
def change
create_table :player_matches do |t|
t.integer :match_id
t.integer :player_id
t.integer :player_shots_on_goal
t.integer :player_goals_scored
t.timestamps
end
end
end
db/migrate/create_team_matches.rb
class CreateTeamMatches < ActiveRecord::Migration
def change
create_table :team_matches do |t|
t.integer :match_id
t.integer :team_id
t.integer :team_points
t.timestamps
end
end
end
Edit1: #Mischa should share credit here! :)
Edit2: Sorry about the many versions, I totally underestimated this problem.
Player Has and belongs to Many Match
That table should contain the details of the player playing that match. For example for which team he played, from which minute (since players can change) etc.
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
i am searching for a solution of my little problem - maybe you wanna help ^^
I have in Ruby on Rails modeled to classes "Person" and "Contact". A Person can have many contacts and a Contact can have one specific person and describes this relation with a value
class Person < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :person
has_one :person #how to rename this?
end
In the table of the Person is nothing special, or related column to contact, but the contact table-script looks like this
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.references :person #how to rename this eather?
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
as i written in the source code - i dont know how to rename the second relation to person - if you can give me a hint i would be very appreciated =)
greetings
Klaf
class Person < ActiveRecord::Base
has_many :contacts
end
class Contact < ActiveRecord::Base
belongs_to :person
belongs_to :contact, :class_name => "Person"
end
#in migration
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.integer :contact_id
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
What about this:
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.references :person
t.string :person_description
t.integer :value
end
end
def self.down
drop_table :contacts
end
end
remove has_one :person from Contact.
To get the description:
some_contact.person_description
I'd rename the :belongs_to to 'owner' and leave the :has_one as 'person'.
You don't need the additional has_one x relationship in your Contact model because there is already an implicit 1-1 relationship present because of the belongs_to :person association.
Note that your contacts table should have a person_id integer field to act as the foreign key.