I'm working on a issue with Single Table Inheritance. I have two different types of Users. User model and Trainer model, Trainer user should inherit attributes from the User model. I created a User in the rails console and everything worked. As soon as I attempted to create a Trainer I get the following error.
Rails 5.0.4
ActiveRecord::RecordInvalid: Validation failed: User must exist
Am I setting up my model associations incorrectly?
Here is my User Model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
My Trainer Model
class Trainer < User
has_many :appointments
has_many :clients, through: :appointments
end
Schema for models
create_table "trainers", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", 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.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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "type"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
As you can see from my User model, I added the required :type column
Here is the schema for my client and appointment
create_table "appointments", force: :cascade do |t|
t.integer "client_id"
t.integer "trainer_id"
t.datetime "appointment_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "start_time"
t.datetime "end_time"
t.integer "status", default: 0
end
create_table "clients", force: :cascade do |t|
t.string "name"
t.string "phone_number"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
First I created a user in the console
User.create!(email:'ryan#test.com', password:'asdfasdf', password_confirmation:'asdfasdf')
Then I when on to create a Trainer
Trainer.create!(first_name:'Ryan', last_name:'Bent')
Trainers and Users should be associated. But I didn't think I needed add associations using Single Table Inheritance.
With Single Table Inheritance, one table must have all the attributes that any of the subclasses need (more information). So for your situation, you'd need to add the Trainer columns (first_name, last_name) to the users table as well, and then Users would leave that empty on the table and Trainers would fill them in.
If you want to keep the separate tables, what you are doing is no longer single table and would require some sort of joining between the 2.
Related
Hello i have an issue with my app Rails when i try to create an "Enfant" who belongs to an user and a Nounou but my problem is when i create an "enfant" i'm a user with an ID but, I haven't chosen yet a nounou so i haven't got a nounou_id this is my differents code(i try to put optional: true but it doesn't work :
Models and Schema
class Enfant < ApplicationRecord
belongs_to :user
belongs_to :nounou, optional: true
end
class Nounou < ApplicationRecord
has_many :enfants
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :enfants
end
create_table "enfants", force: :cascade do |t|
t.string "last_name"
t.string "first_name"
t.bigint "nounou_id", null: false
t.bigint "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["nounou_id"], name: "index_enfants_on_nounou_id"
t.index ["user_id"], name: "index_enfants_on_user_id"
end
create_table "nounous", force: :cascade do |t|
t.string "name"
t.integer "price"
t.string "localisation"
t.integer "evaluation"
t.integer "places"
t.string "first_name"
t.string "last_name"
t.string "photo"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, 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.string "photo"
t.string "first_name"
t.string "last_name"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
Thanks a lot it was in my migration file : t.bigint "nounou_id"
t.bigint "user_id", null: false I delete null:false for nounou_id and it works ;)
I ran into a similar problem when attempting to add a user_id column to a cats table. It kept returning the same NotNullViolation Error. This worked for me, to clear the error so that I was able to keep the "null: false" constraint on the column added to the table. Most likely I am running into the error because there are already cats without users. Run the below commands and it should fix the error for you as well. I learned about this trick from this other question.
rails db:drop
rails db:create
rails db:migrate --trace
There are two problems with the null: false option:
It doesn't consider that the belongs_to association could be optional.
If there are already records in the database, running the migration will generate an Exception, as there is not a default value (in PostgreSQL, PG::NotNullViolation: ERROR: column "user_id" contains null values).
Here's the reference.
Solution:
Your form probably is sending nounou_id as nil or something. You need to verify that by inspecting your params reaching your create method.
You have made nounou_id optional in model only but you need to run a migration to make it optional in db too where it clearly says it can't be false (null: false).
You can take help for that migration from here.
You should modify your enfant_params method in rails:
def enfant_params
params.require(:enfant).permit(:last_name, :first_name, :user_id, :nounou_id)
end
I am confident that this will solve your issue but if you still need help, update your question with your form code, create action and enfant_params and updated schema.
Good Luck.
I have two models: Account and Profile. In Account I have role column. I need to add role column to profiles table.
I include in Profile has_one :account association and belongs_to :profile in Account model. I think the solution is near that.
profile.rb
class Profile < ApplicationRecord
has_one :account
end
acount.rb
class Account < ApplicationRecord
devise :registerable, :database_authenticatable, :rememberable,
:trackable, :confirmable, :lockable, :recoverable, :validatable
belongs_to :profile, foreign_key: 'profile_id'
enum role: %i[user admin]
end
schema.rb
create_table "accounts", 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.string "remember_token"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "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.bigint "profile_id", null: false
t.integer "role", default: 0
t.index ["profile_id"], name: "index_accounts_on_profile_id"
end
create_table "profiles", force: :cascade do |t|
t.string "last_name", null: false
t.string "first_name", null: false
t.string "middle_name"
t.string "email", null: false
t.text "about"
t.date "hire_date", null: false
end
I want to which is in profiles table to be added in column Account.role.
how about just using a function which access the role data from accounts
class Profile < ApplicationRecord
def role
return account.role unless account.nil?
end
end
This is my first publication in stack overflow, I hope you can help me.
I'm working with RoR and PostgreSQL, gem 'devise'.
In rails console I am trying to delete data from the "Competitor" table, but I have the following error and I have not been able to solve it.
2.4.1 :006 > c.destroy(c)
ActiveRecord::UnknownPrimaryKey: Unknown primary key for table competitors in model Competitor.
This is my competitors table, which it's was generate with model of gem devise
create_table "competitors", id: false, 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.bigint "rut"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "lastname"
t.integer "phone"
t.date "dateOfBirth"
t.boolean "gender"
t.string "numberSerie"
t.string "otp_secret_key"
t.integer "otp_module", default: 0
t.index ["email"], name: "index_competitors_on_email", unique: true
t.index ["reset_password_token"], name: "index_competitors_on_reset_password_token", unique: true
t.index ["rut"], name: "index_competitors_on_rut", unique: true
endere
and this is the model
class Competitor < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :raffle_registers, primary_key: 'rut', foreign_key: 'rutCompetitors'
has_many :accountpays
has_one :found
#otp model to make it use TFA
has_one_time_password
enum otp_module: { disabled: 0, enabled: 1 }, _prefix: true
attr_accessor :otp_code_token
end
You generated the competitors table without primary key. Checkout this line:
create_table "competitors", id: false, force: :cascade do |t|
The id: false is your issue. Check the migration to create the competitors table and set a primary key (or create a new migration adding a primary key to it).
Useful resource: https://stackoverflow.com/a/10079409/740394
I have a Rails Api with models, controllers, and serializers. The database is set up, and I have made several migrations, all of which have resulted in corresponding changes to the schema. However, nothing is being persisted to the database, either in the rails console or from the seed data. For instance, when I try to run User.create in the console, I see this message appear:
2.3.3 :003 > User.create
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> #<User id: nil, email: "", created_at: nil, updated_at: nil>
Similarly, I have this data in my seeds file:
users = User.create([{ email: 'adam#adam.com' }, { email: 'ryan#ryan.com'
}])
BankAccount.create(name: 'Adams Chase Checking Account', user_id: users.first)
When I run rake db:seed and attempt to call User.all or BankAccount.all in the rails console, I am given an empty array in both cases. I have heard of errors like this being caused by unmet validations on the models, but my models do not have any validations. I am at a loss as to what could be causing this issue. Any help is greatly appreciated! Also, for what it's worth, this project uses Rails 5.1.4, and I have only used 4.x.x previously. Here is the User model (using devise):
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :bank_accounts
has_many :credit_cards
has_many :investments
has_many :loans
has_many :assets
has_many :recurring_payments, through: :bank_accounts
has_many :recurring_payments, through: :credit_cards
has_many :recurring_payments, through: :investments
has_many :recurring_payments, through: :loans
end
And here is the bank account model:
class BankAccount < ApplicationRecord
belongs_to :user
has_many :recurring_payments
accepts_nested_attributes_for :recurring_payments
end
Here is the full schema:
ActiveRecord::Schema.define(version: 20180205231948) do
create_table "assets", force: :cascade do |t|
t.string "name"
t.integer "value"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "bank_accounts", force: :cascade do |t|
t.string "name"
t.integer "balance"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "credit_cards", force: :cascade do |t|
t.string "provider"
t.integer "balance"
t.integer "interest_rate"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "investments", force: :cascade do |t|
t.string "name"
t.integer "value"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "loans", force: :cascade do |t|
t.integer "user_id"
t.integer "interest_rate"
t.integer "remaining_balance"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "recurring_payments", force: :cascade do |t|
t.string "source"
t.boolean "status"
t.date "pay_date"
t.integer "pay_amount"
t.integer "duration"
t.integer "bank_account_id"
t.integer "credit_card_id"
t.integer "loan_id"
t.integer "investment_id"
t.datetime "created_at", null: false
t.datetime "updated_at", 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.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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name:
"index_users_on_reset_password_token", unique: true
end
end
My guess is this.
users = User.create([{ email: 'adam#adam.com' }, { email: 'ryan#ryan.com' }])
Devise validates the default password before saving (6 characters minimum). Try running this command in console and see if it throws any errors?
user = User.create(email: 'adam#adam.com')
user.errors
Hello I'm getting a rollback transaction when I try to create a Bid from the rails console. These are my models:
Product Model
class Product < ApplicationRecord
belongs_to :user
belongs_to :category
has_many :ratings
has_many :bids
end
Bid model:
class Bid < ApplicationRecord
belongs_to :products
belongs_to :user
end
User model:
class User < ApplicationRecord
has_many :products
has_many :ratings
has_many :bids
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
And this is my schema:
ActiveRecord::Schema.define(version: 20161231124005) do
create_table "bids", force: :cascade do |t|
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "product_id"
t.index ["product_id"], name: "index_bids_on_product_id"
t.index ["user_id"], name: "index_bids_on_user_id"
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "image_url"
t.integer "price"
t.datetime "deadline"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "category_id"
end
create_table "ratings", force: :cascade do |t|
t.integer "rating"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "product_id"
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.datetime "created_at", null: false
t.datetime "updated_at", 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
end
Although I tried to create like so: Bid.create(amount: 500, user_id: 1, product_id:6) it doesn't save because of the rollback transaction.
Thanks in advance
The code you posted doesn't really help. You should also add the logs.
Before posting any logs, I'd try b = Bid.new(amount: 500, user_id: 1, product_id: 6) and b.save in the console. After that, do b.errors and see what's causing the rollback.
EDIT: Add .save.
EEDIT: For anyone experiencing the same problem, the issue was with the Bid model referencing a Product wrong.
When using belongs_to, the model should be singular, not plural. Ex: belongs_to: apple not belongs_to: apples