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.
Related
I have a base class Place and multiple sub-classes using STI conventions. I have a separate model Post, which belongs_to one of the sub-classes of Place:
class Place < ApplicationRecord
end
class SubPlace < Place
has_many :posts, class_name: "SubPlace", foreign_key: "sub_place_id"
end
class Post < ApplicationRecord
belongs_to :sub_place, class_name: "SubPlace", foreign_key: "sub_place_id"
end
It is possible to save a new Post record using Rails console, but I get the following error when trying to find Posts for a specific SubPlace:
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column places.sub_place_id does not exist)
Is there a way to make this work, or must my associations relate to the base class only?
Added Schema:
create_table "posts", force: :cascade do |t|
t.string "title"
t.bigint "sub_place_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["sub_place_id"], name: "index_posts_on_sub_place_id"
end
create_table "places", force: :cascade do |t|
t.string "name"
t.string "type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
A better way to handle assocations and STI is to just setup the assocations to the base class:
class Place < ApplicationRecord
end
class SubPlace < Place
has_many :posts, foreign_key: 'place_id', inverse_of: 'place'
end
class AnotherKindOfPlace < Place
has_many :posts, foreign_key: 'place_id', inverse_of: 'place'
end
class Post < ApplicationRecord
belongs_to :place
end
This keeps things nice and simple since Post does not know or care that there are different kinds of places. When you access #post.place ActiveRecord reads the places.type column and will instanciate the correct subtype.
If the base Post class also has the association you just write it as:
class Place < ApplicationRecord
has_many :posts, foreign_key: 'place_id', inverse_of: 'place'
end
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column
places.sub_place_id does not exist)
Your association in SubPlace is not valid. You should re-write that to just
class SubPlace < Place
has_many :posts
end
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?
I have a model named Letter and an other one named LetterTracking :
class Letter < ApplicationRecord
has_many :letter_trackings, as: :trackable
end
and:
class LetterTracking < ApplicationRecord
belongs_to :letter
has_many :letter_trackings, as: :trackable
end
this is my create table migration for Letter Tracking:
class CreateLetterTrackings < ActiveRecord::Migration[5.0]
def change
create_table :letter_trackings do |t|
t.integer :trackable_id, default: 0, null: false, unique: true
t.string :trackable_type
t.text :paraph
t.string :status
t.string :assignee
t.belongs_to :letter
t.timestamps
end
end
end
as you can see in below screen shots when I select a tracking record for the second tracking the relation is ok but when ever I add the third letter tracking the second one relation removes and the last one keeps the association.
What I want is to keep the letter tracking in each record not by the last one. I mean some thing like nested records in which I can keep the related records.
any Idea ?
Thank you
First of all as a second thought the polymorphic relation seems quite useless for keeping track in this case. The thing which fits best here is tree based relation I suppose.
this is my LetterTracking.rb
class LetterTracking < ApplicationRecord
belongs_to :letter
has_many :children, class_name: "LetterTracking", foreign_key: "parent_id"
belongs_to :parent, class_name: "LetterTracking"
end
and this is my letter.rb
class Letter < ApplicationRecord
has_many :letter_trackings
end
and finaly the LetterTrackings Migration:
class CreateLetterTrackings < ActiveRecord::Migration[5.0]
def change
create_table :letter_trackings do |t|
t.references :parent, index: true
t.text :paraph
t.string :status
t.string :assignee
t.belongs_to :letter, index: true
t.timestamps
end
end
end
Now I can have the records of the lettertrackings join together like a tree while keeping the letter id in every single record! Yep :)
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
I'm trying to create a many to many relationship between two models in Rails 3.2.11.
A User can be associated with many Incidents and vice versa.
class User < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
has_many :incident_participants, foreign_key: "participant_id"
has_many :participated_incidents, through: :incident_participants
end
class Incident < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
has_many :incident_participants, foreign_key: "participated_incident_id"
has_many :participants, through: :incident_participants
end
The join table:
class IncidentParticipant < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
t.belongs_to :participant, class_name: "User"
t.belongs_to :participated_incident, class_name: "Incident"
end
Table for IncidentParticipants
create_table "incident_participants", :force => true do |t|
t.integer "participant_id"
t.integer "participated_incident_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
So, why doesn't rails get this relationship? When I try to do #incident.participants in my view I get this error:
"Could not find the source association(s) :participant or
:participants in model IncidentParticipant. Try 'has_many
:participants, :through => :incident_participants, :source => '.
Is it one of ?"
Any ideas?
Try taking out the t.belongs_to and replace with belongs_to.
To create a many to many association you should consider creating an association table. That is to say you will have two 1-M relationships that point to a sort interim table. For instance:
In your first model:
class Example < ActiveRecord::Base
has_and_belongs_to_many :example2
end
In your second model:
class Example2 < ActiveRecord::Base
has_and_belongs_to_many :example
end
Then you need to write a migration to link the two tables together:
class CreateTableExamplesExamples2 < ActiveRecord::Migration
create_table :examples_examples2 do |t|
t.integer :example_id
t.integer :example2_id
end
end
Then just let rails magic work. Check out the guides for more information.