I've got two models Wallet and FakeWallet. The Wallet should have one FakeWallet and it should be identified through wallet_type and external_id. It means I need to add references based on wallets external_id field.
Standard migration will be:
# rails g migration addReferencesToFakeWallets wallet:references
class AddReferencesToFakeWallets < ActiveRecord::Migration[6.1]
def change
add_reference :fake_wallets, :wallet, null: false, foreign_key: true
end
end
After rails db:migrate produces me:
t.bigint "wallet_id", null: false
t.index ["wallet_id"], name: "index_fake_wallets_on_wallet_id"
How to bind these two models by external_id instead of wallet_id ?
[EDIT]
# schema.rb after suggestion from comments
create_table "fake_wallets", force: :cascade do |t|
t.decimal "balance", default: "0.0"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "external_id"
t.index ["external_id"], name: "index_fake_wallets_on_external_id"
end
create_table "wallets", force: :cascade do |t|
t.integer "wallet_type"
t.string "external_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
Related
I have started my project with a Users table and have since migrated to using an Accounts table. In the process I have an old reference to the Users table still in my schema.rb file and I need to remove it and create a new reference, or update the reference.
I am trying to work out a migration that will allow me to do this, however it keeps throwing an error as there's no Users table and when it did exist, it never had an account_id , which you can see referenced in my schema.rb file.
I really just need my schema.rb file to update
"add_foreign_key "likes", "users", column: "account_id"
to
add_foreign_key "likes", "accounts", column: "account_id"
But am finding this impossible to do with a migration without generating an error.
Any suggestions?
ActiveRecord::Schema.define(version: 2022_01_18_013836) do
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", precision: 6
t.datetime "remember_created_at", precision: 6
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "username"
t.string "first_name"
t.string "last_name"
t.index ["email"], name: "index_accounts_on_email", unique: true
t.index ["reset_password_token"], name: "index_accounts_on_reset_password_token", unique: true
end
create_table "likes", force: :cascade do |t|
t.integer "account_id", null: false
t.integer "product_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_likes_on_account_id"
t.index ["product_id"], name: "index_likes_on_product_id"
end
create_table "products", force: :cascade do |t|
t.string "product_name"
t.string "product_category"
t.string "product_type"
t.string "product_image"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.text "product_description"
t.string "product_country"
end
add_foreign_key "likes", "products"
add_foreign_key "likes", "users", column: "account_id"
end
Best way to resolve this is to create a migration that adds users back with only account_id then remove the foreign key, and drop the user table again.
Should be doable in 1 migration, however I went about it as follows.
I ended up creating a new Users table with just an account_id:integer
Created a migration to remove_foreign_key
Then created a migration to then drop that Users table again.
Schema file is looking correct now and I have all the migrations to trace my changes.
I am making a notes app using Active Admin for the first time and I am running into an error that confuses me because the relationship exists my migrations are present as far as I can see in the schema. I have 2 models currently Note that belongs_to Content and Content has_many :notes . I am trying to customize my show for Contents so it will display differently as seen below but I keep getting a no method error for notes this relationship is present and should work as it is a foreign key between both tables?
class Note < ApplicationRecord
belongs_to :content
end
class Content < ApplicationRecord
has_many :notes
end
ActiveAdmin.register Content do
permit_params :name, note_ids: []
show title: 'Test' do
h3 'You have ' + pluralize(content.notes.count, 'note') + ' referencing ' + `#{content.name}`
end
ActiveRecord::Schema.define(version: 2021_05_06_140826) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "active_admin_comments", force: :cascade do |t|
t.string "namespace"
t.text "body"
t.string "resource_type"
t.bigint "resource_id"
t.string "author_type"
t.bigint "author_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
t.index ["namespace"], name: "index_active_admin_comments_on_namespace"
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
end
create_table "admin_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.index ["email"], name: "index_admin_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
end
create_table "contents", 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 "notes", force: :cascade do |t|
t.string "title"
t.text "body"
t.bigint "content_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["content_id"], name: "index_notes_on_content_id"
end
add_foreign_key "notes", "contents"
end
Are you sure that content is ActiveRecord object? It looks like it is instance of ActiveSupport SafeBuffer.
I'm developing a app on Rails to sell some products, with a table Users, a table Products and a table Reviews, where the users can write their own reviews on a given product; Now i'm starting to implement the payment system, starting with the monetize gem, but after i added the price field to the Product table and run rails db:seed, causes conflict with the Reviews table... Some advice needed. Present code goes like this:
product.rb
class Product < ApplicationRecord
has_one_attached :photo
has_many :reviews, dependent: :nullify
monetize :price_cents
include PgSearch
pg_search_scope :search_by_full_name, against: [:name]
end
review.rb
class Review < ApplicationRecord
belongs_to :user
belongs_to :product
end
schema.rb
ActiveRecord::Schema.define(version: 2020_11_11_190245) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "products", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "price_cents", default: 0, null: false
end
create_table "reviews", force: :cascade do |t|
t.text "description"
t.bigint "user_id", null: false
t.bigint "product_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["product_id"], name: "index_reviews_on_product_id"
t.index ["user_id"], name: "index_reviews_on_user_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.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "first_name"
t.string "last_name"
t.string "phone_number"
t.string "address"
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
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "reviews", "products"
add_foreign_key "reviews", "users"
end
Sometimes the error goes like this
"PG::NotNullViolation: ERROR: null value in column "product_id" violates not-null constraint"
Thanks for the help
I have created a dummy travel agency with Rails 6 and I am trying to use a rake file to seed data for ships, crusies and customer details etc.
The file: ships.rake looks like this:
namespace :ships do
desc "TODO"
task seed_cabins: :environment do
CreditCard.destroy_all
Address.destroy_all
Customer.destroy_all
Cruise.destroy_all
Ship.destroy_all
p "tables emptied"
5.times do |index|
Ship.create!(name: Faker::Coffee.blend_name, tonnage: Faker::Number.within(range: 10000..100000))
end
p "ships created"
# create cabins for each ship
ships = Ship.all
ships.each do |ship|
5.times do |index|
Cabin.create!(
ship_id: ship.id,
name: "Suite #{index+1}",
beds: Faker::Number.between(from: 1, to: 3),
deck: Faker::Number.between(from: 1, to: 3)
)
end
end
p "Cabins created"
ships = Ship.all
ships.each do |ship|
2.times do |index|
Cruise.create!(
ship_id: ship.id,
name: Faker::Hacker.adjective.capitalize + " " +Faker::Hacker.noun.capitalize+" Cruise"
)
end
end
#create customers
3.times do |index |
Customer.create!(
first_name:Faker::Name.first_name,
last_name:Faker::Name.last_name,
has_good_credit: true,
paid: false
)
end
#give each customer an addresses and credit card
customers = Customer.all
customers.each do | customer|
Address.create!(
street:Faker::Address.street_address,
city:Faker::Address.city,
postcode:Faker::Address.postcode,
customer_id: customer.id
)
year = [2020, 2021,2022, 2023]
organisations =["American Express", "MasterCard", "Visa"]
CreditCard.create!(
customer_id:customer.id,
number:Faker::Number.number(12),
exp_date:year.sample.to_s + "/" + Faker::Number.between(1,12).to_s,
name_on_card: customer.first_name + " " + customer.last_name,
organisation: organisations.sample.to_s
)
end
p "customers created"
end
end
The database schema looks like this:
ActiveRecord::Schema.define(version: 2020_10_27_221059) do
create_table "addresses", force: :cascade do |t|
t.string "street"
t.string "city"
t.string "postcode"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_addresses_on_customer_id"
end
create_table "cabins", force: :cascade do |t|
t.string "name"
t.integer "beds"
t.integer "deck"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cabins_on_ship_id"
end
create_table "credit_cards", force: :cascade do |t|
t.string "number"
t.string "exp_date"
t.string "name_on_card"
t.string "organisation"
t.integer "customer_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["customer_id"], name: "index_credit_cards_on_customer_id"
end
create_table "cruises", force: :cascade do |t|
t.string "name"
t.integer "ship_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["ship_id"], name: "index_cruises_on_ship_id"
end
create_table "customers", force: :cascade do |t|
t.string "last_name"
t.string "first_name"
t.integer "has_good_credit"
t.boolean "paid"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "harbours", force: :cascade do |t|
t.string "name"
t.string "country"
t.string "lat"
t.string "long"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "ships", force: :cascade do |t|
t.string "name"
t.integer "tonnage"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
add_foreign_key "addresses", "customers"
add_foreign_key "cabins", "ships"
add_foreign_key "credit_cards", "customers"
add_foreign_key "cruises", "ships"
end
Essentially, I am just try to run the command: rake ships:seed_cabins and try to generate the data fresh. However, I keep getting the following error:
rake aborted!
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Caused by:
SQLite3::ConstraintException: FOREIGN KEY constraint failed
/home/jonathon/Projects/waad/RailsApps/travelagent/lib/tasks/ships.rake:8:in `block (2 levels) in <main>'
Tasks: TOP => ships:seed_cabins
(See full trace by running task with --trace)
I am aware the order of when the tables are destroyed is an issue and the current order is the closest I can get to the file working. it seems to be the Ship.destroy_all line that is the issue because when I remove it and run the file it runs with no issues!
However, as far as I can see there would be no constraints left on that database once the other tables are cleared that would prevent Ship from being deleted?
If anyone could point me in the right direction I would be very grateful.
You missed destroying the cabins, which are still referencing the ships as foreign key. Hence the foreign key constraint is kicking in.
On a side note, you can make your life easier by adding dependent: :destroy in your associations. For example, in your Ship model, you would add,
class Ship < ApplicationRecord
has_many :cabins, dependent: :destroy
end
Since a cabin doesn't make sense without the corresponding ship. What this will do is, whenever a Ship instance is destroyed, it will destroy the related cabins as well.
I'm trying to add some seed data to my database, but ActiveRecord won't let me create a category without an associated user.
ActiveRecord::Schema.define(version: 2020_07_18_233635) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "categories", force: :cascade do |t|
t.string "name"
t.bigint "user_id"
t.string "image_url"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_categories_on_user_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.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, 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
add_foreign_key "categories", "users"
add_foreign_key "goals", "categories"
end
When I try to create a category:
category = Category.create!({name: 'Fitness', image_url: 'some_url'})
I get this error:
ActiveRecord::RecordInvalid (Validation failed: User must exist)
EDIT:
Here's my Category class:
class Category < ApplicationRecord
belongs_to :user
has_many :goals
end
Prior to Rails 5, the default for a belongs_to association was that it was optional. However, for Rails >= 5, the reverse is true; the presence of an associated object is checked by default. Specify :optional on the association to opt out of that:
class Category < ApplicationRecord
belongs_to :user, optional: true
has_many :goals
end