association is not connected (rails) - ruby-on-rails

I want to display %h4 #{message.user_id.name} with association of message model & user model
I'm getting an error:
Showing /Users/ryousuke/projects/chat-space/app/views/messages/_message.html.haml
undefined method `name' for 3707:Fixnum
Trace of template inclusion: app/views/messages/index.html.haml
I've tried...
to check the association:
class Message < ApplicationRecord
belongs_to :user
belongs_to :group
end
class User < ApplicationRecord
 has_many :messages
has_many :group_users
has_many :groups, through: :group_users
end
to check foreign_key:
create_table "messages", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "content", `enter code here`limit: 65535, null: false
t.string "image"
t.integer "user_id", null: false
t.integer "group_id", null: false
t.index ["group_id"], name: "fk_rails_841b0ae6ac", using: :btree
t.index ["user_id"], name: "fk_rails_273a25a7a6", using: :btree
to check data existence usertable id:3707

user_id returns the ID - a number. What you want is just user, which will return the actual user object.
%h4 #{message.user.name}

Related

How to model the associations properly in rails to perform inner joins in rails?

I have the following models
class RecruitmentPhase < ApplicationRecord
belongs_to :cohort, optional: true
belongs_to :parent, class_name: 'Cohort', required: false
has_many :patient_phases, dependent: :destroy, class_name: 'PatientPhase', foreign_key: :phase_id, primary_key: :phase_id
has_many :patients, through: :patient_phases, class_name: 'Patient', foreign_key: :patient_id, primary_key: :patient_id
def phase_name_ret
phase_name
end
end
class PatientPhase < ApplicationRecord
belongs_to :patients, foreign_key: 'patient_id', class_name: 'Patient', primary_key: 'patient_id'
belongs_to :recruitment_phase, foreign_key: :phase_id
self.primary_key = :phase_id
end
class Patient < ApplicationRecord
has_many :patient_phases, foreign_key: 'patient_id', primary_key: :patient_id
belongs_to :patient_phase
has_one :recruitment_phase, through: :patient_phase
end
and my schema is as follows
create_table "recruitment_phases", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "phase_id"
t.string "phase_token"
t.string "phase_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "source_id"
t.bigint "cohort_id"
t.index ["cohort_id"], name: "index_recruitment_phases_on_cohort_id"
t.index ["source_id"], name: "index_recruitment_phases_on_source_id"
end
create_table "patients", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "patient_id"
t.integer "recruitment_code_id"
t.string "disease_code_id"
t.string "sex"
t.integer "yob"
t.date "date_imported"
t.integer "is_exported"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "patient_phase_id"
t.index ["patient_phase_id"], name: "index_patients_on_patient_phase_id"
end
create_table "patient_phases", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
t.integer "patient_id"
t.integer "phase_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "recruitment_phase_id"
t.index ["recruitment_phase_id"], name: "index_patient_phases_on_recruitment_phase_id"
end
I am trying to perform joins on the tables as follows in rails console
RecruitmentPhase.joins(:patient_phases, :patients).where(:patients => {disease_code_id: 'KIN'}).select('distinct patients.disease_code_id', 'recruitment_phases.phase_name', 'recruitment_phases.phase_id')
And I am getting the translated query to SQL as
SELECT distinct disease_code_id FROM `recruitment_phases`
INNER JOIN `patient_phases` ON `patient_phases`.`phase_id` = `recruitment_phases`.`phase_id`
INNER JOIN `patient_phases` `patient_phases_recruitment_phases_join` ON `patient_phases_recruitment_phases_join`.`phase_id` = `recruitment_phases`.`phase_id`
INNER JOIN `patients` ON `patients`.`patient_id` = `patient_phases_recruitment_phases_join`.`patient_id`
WHERE `patients`.`disease_code_id` = 'KIN' LIMIT 11
But I need the query as follows
SELECT distinct patients.disease_code_id,
recruitment_phases.phase_name, recruitment_phases.phase_id FROM `patients`
join patient_phases on patient_phases.patient_id = patients.patient_id
join recruitment_phases on recruitment_phases.phase_id = patient_phases.phase_id
WHERE (patients.disease_code_id = 'KIN') LIMIT 11
I know some how my associations are not correct, as I am a trying to learn more on such concepts, can you give me a hint on how I can approach the above problem?.
I resolved my question. It was just using the following
RecruitmentPhase.joins(patients: :patient_phases).where(:patients => {disease_code_id: 'KIN'}).select('distinct patients.disease_code_id', 'recruitment_phases.phase_name', 'recruitment_phases.phase_id')

migrate file exists but no model for rails application

migrate file exists but no model for rails application.There are user and book model.I created join table between user and book model.
I write console : rails g migration CreateJoinTableBooksUsers books users
rake:db migrate
**schema.rb**
create_table "books", force: :cascade do |t|
t.string "title"
t.string "author"
t.integer "page_count"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.boolean "status"
t.string "user_id"
t.boolean "barter_status"
end
create_table "books_users", id: false, force: :cascade do |t|
t.bigint "book_id", null: false
t.bigint "user_id", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "username"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end
add_foreign_key "comments", "books"
add_foreign_key "comments", "users"
end
**migrate**
class CreateJoinTableBooksUsers < ActiveRecord::Migration[6.0]
def change
create_join_table :books, :users do |t|
t.index [:book_id, :user_id]
t.index [:user_id, :book_id]
end
end
end
A migration creates the tables in the database but doesn't create anything else.
But, for a true join table, you don't need a model:
https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
# app/models/user.rb
class User < ApplicationRecord
has_and_belongs_to_many :books
end
# app/models/books.rb
class Book < ApplicationRecord
has_and_belongs_to_many :users
end
IF you need scopes, callbacks, or methods on BooksUsers, you can use the has_many :through option:
https://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many
# app/models/user.rb
class User < ApplicationRecord
has_many :books_users
has_many :books, through: :books_users
end
# app/models/books.rb
class Book < ApplicationRecord
has_many :books_users
has_many :users, through: :books_users
end
In this case, you'll need to generate a model:
rails generate model BooksUsers

SQLite3::SQLException: no such table

Server log screencap
Hi everyone!
Was writing a rating system for an airBnb style project so i made the objects Host and Guest as reference to the User object.
But something is wrong in my code:
SQLite3::SQLException: no such table: main.hosts
In fact the method looks for host table i dont have cause it should be associated to the Users one.
migration
class CreateReviews < ActiveRecord::Migration[6.0]
def change
create_table :reviews do |t|
t.text :comment
t.integer :star, default: 1
t.references :car, foreign_key: true
t.references :reservation, foreign_key: true
t.references :guest, foreign_key: true
t.references :host, foreign_key: true
t.string :type
t.timestamps
end
end
end
Schema
create_table "reviews", force: :cascade do |t|
t.text "comment"
t.integer "star", default: 1
t.integer "car_id"
t.integer "reservation_id"
t.integer "guest_id"
t.integer "host_id"
t.string "type"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["car_id"], name: "index_reviews_on_car_id"
t.index ["guest_id"], name: "index_reviews_on_guest_id"
t.index ["host_id"], name: "index_reviews_on_host_id"
t.index ["reservation_id"], name: "index_reviews_on_reservation_id"
Models:
class HostReview < Review
belongs_to :host, class_name: "User"
end
class User < ApplicationRecord
....
has_many :host_reviews, class_name: "HostReview", foreign_key: "host_id"
I think you can do something like this:
t.references :host, references: :users, foreign_key: true
or alternatively
t.integer :host_id
and then
add_foreign_key :reviews, :users, column: :host_id

Database definition with nested attributes and HABTM

I am trying to track GPS satellites as they cross the sky. I receive 'SKY' messages every 5 seconds, containing location and signal strength data for each satellite currently visible. The database contains tables for 'skies', 'sats', 'tracks' and 'points'. The idea is that each sky received will add a location point to each of its satellite's track. Schema is...
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
The model definitions are...
class Sky < ApplicationRecord
include ActionView::Helpers::NumberHelper
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
When a sky message is received, it checks the previous sky message to see which of it's satellites also existed there. For those found, the point is just added to that satellite's track table. If the satellite was not visible in the last sky, a new sat record is created, and its location 'point' is added to the new sat's track.
Note that the point record has foreign keys for both the track, and the sky records.
Initially, I had all this working, but I was creating the sky record, then creating the sat/track records (if needed), then saving the point. A power failure while processing a sky message caused the database to contain a sat/track with no points. I realize I could just surround all this processing with a transaction block, but thought a cleaner solution would be to create all the various components for a sky message in memory and when complete save the whole batch with a single new_sky.save.
But try as I may, I don't seem to be able to get the proper combination 'reverse_of', 'nested_attributes' and other definition attributes to successfully save the results. With everything configured as listed here, I am currently getting the following while processing the first satellite in the first sky message received...
D, [2020-05-03 10:37:32.410281000 -0500 CDT#83744] DEBUG -- GpsComms: ************* This sat (#8) not found in previous SKY, create new *************
E, [2020-05-03 10:37:32.436055000 -0500 CDT#83744] ERROR -- GpsComms: Sat Processing Failed
E, [2020-05-03 10:37:32.436454000 -0500 CDT#83744] ERROR -- GpsComms: {:Rescue=>"#<ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)>"}
E, [2020-05-03 10:37:32.436786000 -0500 CDT#83744] ERROR -- GpsComms: Could not find the inverse association for track (:point in Track) - (ActiveRecord::InverseOfAssociationNotFoundError)
With other combinations of options (reverse_of:, optional:, etc) I get error messages stating various object must exist.
I think I'm close. I'm hoping somebody can figure out the correct combination of definitions to get this to work.
Thanks for any help,
UPDATE:
I believed that the error above ("Could not find the inverse association for track (:point in Track)") was being generated when attempting to save the new sky object. It is actually being generated when the new point is being added to the points collection.
At this point I have created the new sky with
sky=Sky.new( parameters)
The satellite has been created with
sat=sky.sats.build(parameters)
The track with
track=sat.build_track(empty)
Now I can do either
new_point=sat.track.points.build(parameters)
or
sat.track.points << Point.new(parameters)
to generate the inverse assoc error.
Hope this helps!
UPDATE:
Thanks to the suggestion from Eyselandic below -- here is a run-able file. It errors out on the last line with the 'inverse association' error.
# Activate the gem you are reporting the issue against.
gem 'activerecord', '6.0.0'
require 'active_record'
require 'minitest/autorun'
require 'logger'
# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(
adapter: 'postgresql',
database: 'database_name',
username: 'username',
password: 'password'
)
ActiveRecord::Base.logger = Logger.new(STDOUT)
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
ActiveRecord::Schema.define do
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
end
class Sky < ApplicationRecord
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
class BugTest < Minitest::Test
def test_association_stuff
sky_attr= {
:klass=>"SKY",
:device=>"/dev/ttyAMA0",
:xdop=>0.62,
:ydop=>0.89,
:vdop=>0.94,
:tdop=>1.15,
:hdop=>1.23,
:gdop=>2.28,
:pdop=>1.55
}
sky = Sky.new(sky_attr)
sat = sky.sats.build(:PRN=>7)
track = sat.build_track
point_attr= {
:PRN=>7,
:el=>61,
:az=>340,
:ss=>21,
:used=>true,
# :sky_id=>nil,
:duplicate=>false
}
point=sat.track.points.build( point_attr)
sky.save
end
end
Error:
Error:
BugTest#test_association_stuff:
ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:240:in `check_validity_of_inverse!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:474:in `check_validity!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:43:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:286:in `inverse_association_for'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:107:in `set_inverse_instance'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:187:in `initialize_attributes'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:318:in `block in build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/core.rb:328:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:158:in `build_association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:317:in `build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_association.rb:108:in `build'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_proxy.rb:316:in `build'
active_record_gem.rb:136:in `test_association_stuff'

Rails association in model error

I am using rails 4.2.0. and I am getting this error:
ActiveRecord::HasManyThroughAssociationNotFoundError:
Could not find the association :taggings in model Article
Here are my models:
class Tag < ActiveRecord::Base
has_many :taggings
has_many :articles, :through => :taggings
end
class Article < ActiveRecord::Base
has_many :comments
has_many :taggings
has_many :tags, :through => :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :article
end
Tagging is an intermediary model for the many-to-many relationship between Article and Tag.
And if it helps, my schema:
ActiveRecord::Schema.define(version: 20150224161732) do
create_table "articles", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "comments", force: :cascade do |t|
t.string "author_name"
t.text "body"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "comments", ["article_id"], name: "index_comments_on_article_id"
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "taggings", ["article_id"], name: "index_taggings_on_article_id"
add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id"
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I run this code in rails console to test my associations:
a = Article.first
a.tags.create name: "cool"
And I get the above error.
I have seen similar questions where the response "if you have through: :x, you have to have has_many :x first," but I don't think that is my issue.
This might be a silly question, but have you tried creating a Tagging independent of the Article model? If you haven't, than it could be something messed up with the database not having the Tagging model. Otherwise, associations look fine and should work. The only other thing I can think of is incorrect file names for your models folder

Resources