Any suggestions on how to set up this relationship? A Match has two Country on each side, right?
However, Rails Admin is complaining that this is not the right way.
create_table "countries", force: true do |t|
t.string "name"
t.string "flag"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "matches", force: true do |t|
t.integer "country_a"
t.integer "country_b"
t.integer "score_country_a"
t.integer "score_country_b"
end
class Country < ActiveRecord::Base
belongs_to :matches
end
class Match < ActiveRecord::Base
belongs_to :country_side_a, foreign_key: :country_a
belongs_to :country_side_b, foreign_key: :country_b
end
How can I configure these relationships properly?
Here's how I ultimately set up the relations:
class Country < ActiveRecord::Base
has_many :matches_a, foreign_key: :country_a, class_name: "Match"
has_many :matches_b, foreign_key: :country_b, class_name: "Match"
end
class Match < ActiveRecord::Base
belongs_to :country_side_a, foreign_key: :country_a, class_name: "Country"
belongs_to :country_side_b, foreign_key: :country_b, class_name: "Country"
end
Country needs to have a has_one :matches, if you want a one to one mapping, or has_many :matches if you want a many to many relationship.
Have a read about how to set up a one to one/many relationship here:
http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association
Related
I have 4 models.
UserModel
SkillModel
UserSkillModel
PreferenceSkillModel
Association I used:
UserModel
has_many :skills, through: :user_skills
has_many :user_skills
has_many :skills, :through: :preference_skills
has_many :preference_skills
SkillModel
has_many :users, through: :user_skills
has_many :users_skills
has_many :users, :through: :preference_skills
has_many :preference_skills
UserSkillModel
belongs_to :user
belongs_to :skill
PreferenceSkillModel
belongs_to :user
belongs_to :skill
Schema:
create_table "preference_skills", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.integer "user_id", default: 0
t.integer "skill_id", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "user_skills", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.integer "user_id"
t.integer "skill_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "skills", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "name", default: ""
t.integer "skill_count", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
How can I implement this association in a correct way?
How can I implement this association in a correct way?
What is correct may depend on what you are trying to do. The following is correct, by naming separate associations for users-skills and users-preference_skills.
class User
has_many :user_skills
has_many :my_skills, through: :user_skills, class_name: 'Skill'
has_many :preference_skills
has_many :my_preference_skills, :through: :preference_skills, class_name: 'Skill'
...
end
class SkillModel
has_many :users_skills
has_many :direct_users, through: :user_skills, class_name: 'User'
has_many :preference_skills
has_many :preference_users, :through: :preference_skills, class_name: 'User'
...
end
If you want one collection with all the skills you need to use STI or polymorphism. Read the Rails Guides for more information.
I don't think there's a need for separate user_skills & preference_skills models.
You can use STI here like -
skill.rb
Skill < ApplicationRecord
end
user_skill.rb
UserSkill < Skill
end
preference_skill.rb
PreferenceSkill < Skill
end
Note: The Skill model that I've used is different from what you are assuming.
You might want to rename your current Skills model to more explainatory name like SkillDetail.
After this you can have your associations like -
class User < AR
has_many :skills
has_many :skill_details, through: :skills
end
class Skill < AR
belongs_to :user
belongs_to :skill_detail
end
class SkillDetail < AR
has_many :skills
has_many :users, through: :skills
end
P.S. Do some research on Single Table Inheritance (STI)
Hope this helps.
Also note that you got a downvote because this is a very vague question & you are directly asking to implement a business logic.
I have two models in use at this point: Airports and Flights.
Flights belong to both an origin airport and destination airport. When I try to create a Flight model instance, I get the following error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.destination_airports
I have set up my code to match the example here: https://www.theodinproject.com/courses/ruby-on-rails/lessons/active-record-associations
I've researched the problem (here and elsewhere), but can't turn up anything that seems to match my situation. I can't figure out what's going wrong. Has to be something simple. Something with the migrations, maybe? Thanks in advance for the help.
Relevant code:
Airport model:
class Airport < ApplicationRecord
has_many :departing_flights, foreign_key: "origin_airport_id",
class_name: "Flight"
has_many :arriving_flights, foreign_key: "destination_airport_id",
class_name: "Flight"
validates :abbreviation, presence: true, length: { is: 3 }
end
Flight model:
class Flight < ApplicationRecord
belongs_to :origin_airport, class_name: "Airport"
belongs_to :destination_airport, class_name: "Airport"
has_many :bookings
has_many :passengers, through: :bookings
end
Migrations:
class CreateAirports < ActiveRecord::Migration[5.1]
def change
create_table :airports do |t|
t.string :abbreviation
t.string :full_name
t.string :city
t.string :state
t.string :zip
t.timestamps
end
end
end
class CreateFlights < ActiveRecord::Migration[5.1]
def change
create_table :flights do |t|
t.references :origin_airport, foreign_key: true
t.references :destination_airport, foreign_key: true
t.datetime :depart_time
t.datetime :arrive_time
t.integer :capacity
t.string :airline
t.string :flight_number
t.timestamps
end
end
end
Check the filenames of the migrations, perhaps they are not being run in the correct order?
Also, you may just need to run the migration in the right environment (RAILS_ENV=development)
Update: I found the (an?) answer - changing the migration for the flights table to replace t.references with t.integer and the column name with "x_id" corrects the problem. So, does references only work if using the model name for the column id?
Using Ruby on Rails, I think I need to create a self-referential has_many association to model words in Chinese.
Background:
Each word is a composite of multiple component words.
For example, if I have three words, 'ni', 'hao', and 'nihao', I want to be able to do:
nihao.components = ['ni', 'hao']
and
'ni'.composites = ['nihao']
'hao'.composites =['nihao']
I don't believe this should be a hierarchical association (I've seen several gems... ) because a word doesn't have 1 or 2 "parents", it has 0, 1, or hundreds of "composites". Likewise a word has 0, 1, or several "components".
I've tried:
class Word < ActiveRecord::Base
has_many :relationships
has_many :components, through: :relationships, foreign_key: :component_id
has_many :composites, through: :relationships, foreign_key: :composite_id
end
class Relationship < ActiveRecord::Base
belongs_to :component, class_name: "Word"
belongs_to :composite, class_name: "Word"
end
This isn't quite correct as I am unable to add components:
nihao.components << ni
(0.2ms) BEGIN
(0.2ms) ROLLBACK
ActiveModel::UnknownAttributeError: unknown attribute 'word_id' for Relationship.
from (irb):5
Database schema:
create_table "relationships", force: :cascade do |t|
t.integer "component_id"
t.integer "composite_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "words", force: :cascade do |t|
t.string "characters"
t.string "pinyin"
t.string "opinyin"
t.string "tpinyin"
t.string "english"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Try this, you were not associating your models properly for this kind of use case.
class Word < ActiveRecord::Base
has_many :component_relationships, class_name: 'Relationship', foreign_key: :composite_id
has_many :composite_relationships, class_name: 'Relationship', foreign_key: :component_id
has_many :components, through: :component_relationships
has_many :composites, through: :composite_relationships
end
class Relationship < ActiveRecord::Base
belongs_to :component, class_name: "Word", foreign_key: :component_id
belongs_to :composite, class_name: "Word", foreign_key: :composite_id
end
I have not tried this, but this should work.
I practice my RoR skills and try develop application to already created DB. It's have 4 tables: testplans, testplan_tcversions,* test_project* and nodes.
I'm code 2 models for this tables:
class TestPlan < ActiveRecord::Base
self.table_name= 'testplans'
belongs_to :test_project
has_many :test_suites, foreign_key: :testplan_id, inverse_of: :test_plan
has_one :node, foreign_key: :id, inverse_of: :test_plan
end
and
class TestSuite < ActiveRecord::Base
self.table_name='testplan_tcversions'
belongs_to :test_plan
has_one :node, foreign_key: id, inverse_of: :test_collection
end
But I get exception uninitialized constant TestPlan::TestSuite when try: #suits=TestPlan.find(4906).test_suites
I found a lot of answers that Models must singular and table must plural, but my Models names are singular, names of tables I point in self.table_name.
What I did wrong?
UPD
This my db:schema:dump
create_table "testplans", force: true do |t|
t.integer "testproject_id"
t.text "notes"
t.integer "active"
t.integer "is_open"
t.integer "is_public"
t.text "api_key"
end
create_table "testplan_tcversions", force: true do |t|
t.integer "testplan_id"
t.integer "tcversion_id"
t.integer "node_order"
t.integer "urgency"
t.integer "platform_id"
t.integer "author_id"
t.datetime "creation_ts"
end
How are your migrations set up?
If they are set up correctly, the relationship between TestSuite and TestPlan should look like this:
class TestPlan < ActiveRecord::Base
has_many :test_suites
end
class TestSuite < ActiveRecord::Base
belongs_to :test_plan
end
For this to work though, your TestSuite migration needs to have a test_plan_id column. That should look like this.
class TestSuite < ActiveRecord::Migration
belongs_to :test_plan
end
If this is set up correctly, you should then be able to call #suits=TestPlan.find(4906).test_suites.
Make sure your table names correspond to your model names. If you don't have a table named 'testplan_tcversions', the association isn't going to work.
So I am developing a rails app that will have two kinds of Users, student/tutor. but I only have one User model (using cancan for auth), so when I try to set up the meeting model (which has one tutor and one student) how do I do this? This is the model:
class Meeting < ActiveRecord::Base
belongs_to :student
belongs_to :tutor
attr_accessible :price, :subject, :time
end
and here's the relevant part of the schema:
create_table "meetings", :force => true do |t|
t.string "subject"
t.integer "student_id"
t.integer "tutor_id"
t.datetime "time"
t.integer "price"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "meetings", ["student_id"], :name => "index_meetings_on_student_id"
add_index "meetings", ["tutor_id"], :name => "index_meetings_on_tutor_id"
Without having to have two extra models containing student and tutor can I use those labels?
one way to do it..
class Meeting < ActiveRecord::Base
belongs to :student, class_name: 'User'
belongs to :tutor, class_name: 'User'
class User < ActiveRecord::Base
has_many :meet_with_students, class_name: 'Meeting', foreign_key: :tutor_id
has_many :students, through: :meet_with_students, source: :student
has_many :meet_with_tutors, class_name: 'Meeting', foreign_key: :student_id
has_many :tutors, through: :meet_with_tutors:, source: :tutor
I think you're looking for class_name:
class Meeting < ActiveRecord::Base
belongs_to :student, class_name: "User"
belongs_to :tutor, class_name: "User"
end