SQLite3::SQLException: no such table - ruby-on-rails

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

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')

How to query an object from one model, starting from another model? Ruby

I am trying to make an association that is not working.
I have the following scope:
ActiveRecord::Schema.define(version: 2020_04_05_125812) do
create_table "accounts", force: :cascade do |t|
t.string "social_network"
t.string "name_account"
t.integer "person_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["person_id"], name: "index_accounts_on_person_id"
end
create_table "lists", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "lists_people", id: false, force: :cascade do |t|
t.integer "list_id", null: false
t.integer "person_id", null: false
end
create_table "people", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "posts", force: :cascade do |t|
t.string "post_text"
t.date "date"
t.string "link"
t.integer "account_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["account_id"], name: "index_posts_on_account_id"
end
add_foreign_key "accounts", "people"
add_foreign_key "posts", "accounts"
end
I wish I could consult, for example:
I want to consult the person named "Test_name"
That person belongs to lists, which is a collection of people. In addition, that person has accounts and those accounts have Posts.
class List < ApplicationRecord
has_and_belongs_to_many :people
end
class Person < ApplicationRecord
has_and_belongs_to_many :lists
end
class Account < ApplicationRecord
has_many :posts
belongs_to :person
end
class Post < ApplicationRecord
belongs_to :account
end
How could I have a return like the one below:
List | Name | social_network
1 | Test_name | facebook
2 | Test_name | twitter
All the queries I make, either return the wrong type, or return only the list.
Problems such as:
List | Name | social_network
1 | Test_name | facebook
2 | Test_name | twitter
1 | Second_name | twitter
And I don't want to see the data "second_name"
I try this:
#lists = List.from(
Person.left_outer_joins(:list).where('people.name LIKE ?', "Renata Rempel"),
:list
)
but, doesn't works =/
To start off with you want to setup a many to many association between Person and List. This can be done with has_and_belongs_to_many but there are many reasons why has_many through: may be a better choice. The primary one is that it will let you add features like keeping track of banned users or when a user joined a list.
# rails g model list_membership member:belongs_to user:belongs_to
class ListMembership < ApplicationRecord
belongs_to :member, class_name: 'Person'
belongs_to :list
end
We then have to fix the foreign key in the association:
class CreateListMemberships < ActiveRecord::Migration[6.0]
def change
create_table :list_memberships do |t|
t.belongs_to :list, null: false, foreign_key: true
t.belongs_to :member, null: false, foreign_key: { to_table: :people }
t.timestamps
end
# can be a good idea to add a compound index
# add_index [:list_id, :member_id], unique: true
end
end
class Person < ApplicationRecord
has_many :list_memberships, foreign_key: :member_id
has_many :lists, through: :list_memberships
has_many :accounts
has_many :posts, through: :accounts
end
class List
has_many :list_memberships
has_many :members,
through: :list_memberships
end
Your from query will not work as your actually selecting rows from people but you just alias the table lists. That won't magically select the right data! If you really wanted to use from you would do:
List.from(
List.joins(:members).where("people.name LIKE ?", "Renata Rempel"),
:lists
).eager_load(members: :posts)
If you want to create a bunch of lists with a random number of members in your seed file you can just do:
ids = 10.times.map do
Person.create!(name: Faker::Name.name).id
end
lists = 10.times.do
List.create!(member_ids: ids.sample(2))
end

Unitialized constant User:Bookings when trying to add data into a join table

I have a User table and a Booking Table that is linked by a create_join_table what holds the user id and booking ids. When a user books a room, i need the id of both the user and new booking to go into that. I am getting the error above and im not sure why.
I have looked online and saw something similar, their class names were plural however I don't think I have that.
booking.rb
class Booking < ApplicationRecord
enum room_type: ["Basic Room", "Deluxe Room", "Super-Deluxe Room", "Piton Suite"]
has_many :join_tables
has_many :users, through: :join_tables
end
user.rb
class User < ApplicationRecord
has_secure_password
validates :email, format: {with: URI::MailTo::EMAIL_REGEXP}, presence: true, uniqueness: true
has_many :join_tables
has_many :bookings, through: :join_tables
end
join_table.rb
class JoinTable < ApplicationRecord
belongs_to :users
belongs_to :bookings
end
bookings_controller.rb
def create
#booking = Booking.create(booking_params)
current_user.bookings << #booking ##Where the error happens
db/schema
ActiveRecord::Schema.define(version: 2019_12_13_181019) do
create_table "bookings", force: :cascade do |t|
t.integer "room_type"
t.date "check_in"
t.date "check_out"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "join_tables", force: :cascade do |t|
t.integer "users_id"
t.integer "bookings_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["bookings_id"], name: "index_join_tables_on_bookings_id"
t.index ["users_id"], name: "index_join_tables_on_users_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
I have just tried to reproduce your problem and I have a similar exception
irb(main):003:0> User.first.bookings
NameError (uninitialized constant User::Bookings)
but, when I change
belongs_to :users
belongs_to :bookings
to
belongs_to :user
belongs_to :booking
in app/models/join_table.rb everything works as expected.
This is how I created the JoinTable model
$ rails generate model JoinTable
class CreateJoinTables < ActiveRecord::Migration[6.0]
def change
create_table :join_tables do |t|
t.references :user
t.references :booking
t.timestamps
end
end
end
As you can see in the belongs_to docs, it is used in the singular form most of the time.

Ruby on Rails 4.2, stack level too deep, associations and delegate()

I understand the cause of a Stack Level Too Deep error. I am failing to spot where/why it is occurring in my code base.
I've implemented a multi-model, multi-step wizard. The first two models (User and Company) are working, it is when I attempt to add in the third (Address) I get the error.
I suspect the error is related to the associations between the models, although I've failed to debug.
The code snippets below function correctly except when I add the 3 lines (marked with comments in the snippet) too the file app/wizards/user_wizard/step1.rb.
Relevant Models
app/models/company.rb
class Company < ActiveRecord::Base
include Validatable::Company
# Associations:
has_many :addresses, inverse_of: :company
accepts_nested_attributes_for :addresses, reject_if: :all_blank
has_many :employees, inverse_of: :company
accepts_nested_attributes_for :employees, reject_if: :all_blank
has_many :licenses, inverse_of: :company
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :vehicles, inverse_of: :company
accepts_nested_attributes_for :vehicles, reject_if: :all_blank
has_one :user, inverse_of: :company
end
app/models/address.rb
class Address < ActiveRecord::Base
# Associations:
belongs_to :company, inverse_of: :addresses
has_many :licenses, inverse_of: :address
accepts_nested_attributes_for :licenses, reject_if: :all_blank
has_many :initial_analyses, inverse_of: :address
accepts_nested_attributes_for :initial_analyses, reject_if: :all_blank
end
app/models/user.rb
class User < ActiveRecord::Base
include SoftDeletable
include Validatable::User
# Constants:
MARKER_ATTRIBUTES = %w[user_name].freeze # get marked with '(deleted)'
DEPENDANT_CHILDREN = %w[none].freeze # child resources to be deleted
# Associations:
belongs_to :role, inverse_of: :users
belongs_to :company, inverse_of: :user
accepts_nested_attributes_for :company, reject_if: :all_blank
has_many :auto_quotes, inverse_of: :user
end
db/schema.rb
ActiveRecord::Schema.define(version: 20170616131833) do
create_table "addresses", force: :cascade do |t|
t.integer "company_id"
t.text "site_name"
t.string "premises_code"
t.string "exempt_premises_code"
t.text "address"
t.string "city"
t.string "county"
t.string "sic_code"
t.string "postcode"
t.string "country"
t.boolean "sic_update"
t.boolean "deleted", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
create_table "companies", force: :cascade do |t|
t.string "company_name"
t.string "registration_number"
t.string "type_of_business"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
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.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.datetime "locked_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_name"
t.datetime "deleted_at"
t.integer "role_id"
t.integer "company_id"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
end
add_index "users", ["company_id"], name: "index_users_on_company_id", unique: true
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count"
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id"
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end
Wizards
app/wizards/user_wizard/base.rb
module UserWizard
class Base
include ActiveModel::Model
STEPS = %w[step1 step2].freeze
attr_accessor :user
delegate(*::User.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :user)
def initialize(user_attributes)
#user = ::User.new(user_attributes)
end
end
end
app/wizards/user_wizard/step1.rb
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#address = #user.company.addresses.build
end
end
end
app/wizards/user_wizard/step2.rb
ommitted as it is irrelevant. code fails before ever instantiating this class
address has an address attribute. So the delegate method is trying to create a method address that will be delegated to address.
I'd suggest this:
module UserWizard
class Step1 < UserWizard::Base
include Validatable::Company
attr_accessor :company
# One of 3 lines triggering circular reference by adding in Address model
attr_accessor :company_address
delegate(*::Company.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company)
# One of 3 lines triggering circular reference by adding in Address model
delegate(*::Address.attribute_names.map {|attr| [attr, "#{attr}="] }.flatten, to: :company_address)
def initialize(user_attributes)
super
#company = #user.build_company
# One of 3 lines triggering circular reference by adding in Address model
#company_address = #user.company.addresses.build
end
end
end

Rails 5 inverse of not working

I'm trying to return JSON API where a show action will
render json: user, include [:books, :friends, :comments]
Problem is, if I try to use the inverse_of in my User and Book model classes like this:
User Serializer
class UserSerializer < ActiveModel::Serializer
...
has_many :friends
has_many :books, inverse_of: :author
...
end
Book Serializer
class BookSerializer < ActiveModel::Serializer
...
belongs_to :author, class_name: "User", inverse_of: :books
...
end
I get an error:
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: books.user_id: SELECT "books".* FROM "books" WHERE "books"."user_id" = ?):
If I remove the inverse_of and has_many from my User serializer, then I don't get any errors, but then the JSON being returned does not contain the included association.
Likewise, the same happens between Comment and User models.
Am I doing something wrong ?
My DB Schema for my two models are:
User Schema
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.string "password_digest"
t.boolean "banned"
t.integer "role_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "photo"
t.boolean "email_confirmed", default: false
t.string "confirm_token"
t.string "password_reset_token"
t.boolean "show_private_info", default: false
t.boolean "show_contact_info", default: false
t.index ["role_id"], name: "index_users_on_role_id"
end
Book Schema
create_table "books", force: :cascade do |t|
t.string "title"
t.boolean "adult_content"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "published"
t.string "cover"
t.text "blurb"
t.index ["author_id"], name: "index_books_on_author_id"
end
When I went to generate my Book model with:
rails generate model books ... author:references
It created this migration file:
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books do |t|
t.string :title
t.boolean :adult_content
t.references :author, foreign_key: true
t.timestamps
end
end
end
I assume that includes the necessary foreign key setup...
Try to change this line in your User model(user.rb):
has_many :books, inverse_of: :author
to
has_many :books, inverse_of: :author, foreign_key: :author_id
You need to tell rails what foreign_key you used if it's not the default one.And the association should be declared in your models, not serializers. In serializer you are adding keys by "has_many", inverse_of does't works here.

Resources