Error while saving floats to PostgreSQL from Rails - ruby-on-rails

I just recently made the switch over to PostgreSQL.. and just wondering about this issue:
PG::Error: ERROR: column "bathrooms" is of type double precision but expression is of type character varying at character 161
HINT: You will need to rewrite or cast the expression.
: INSERT INTO "properties" ("address", "bathrooms", "bedrooms", "city", "country", "created_at", "description", "name", "state", "updated_at", "zip") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING "id"
Migration looks like this:
class CreateProperties < ActiveRecord::Migration
def change
create_table :properties do |t|
t.string :name
t.string :address
t.string :city
t.string :state
t.string :zip
t.string :country
t.float :bedrooms
t.float :bathrooms
t.string :country
t.text :description
t.timestamps
end
end
end

I switched the float to decimal, it seems PostgreSQL is fine with that implicit cast now?
Either way the error is gone, thanks

Related

PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint

I am getting this error when I try to add a new case
PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint DETAIL: Failing row contains (null, nini, momo, 2023-01-21, 2023-01-31, rwe, rwe, Upper, 18, Report_Cards_-_K-9_Three_Term.pdf, application/pdf, 847591, 2023-01-27 01:46:36.772805, ewr, werr, 449, f, f, f, T4-1007-0001_2020.pdf, application/pdf, 60955, 2023-01-27 01:46:36.803862, null, null, null, null, null, null, null, null, null, null, null, null, 2023-01-27 01:46:36.867886, 2023-01-27 01:46:36.867886). : INSERT INTO "cases" ("pt_first_name", "pt_last_name", "date_received", "due_date", "ship", "shade", "finished", "outsourced", "mould", "upper_lower", "implant_brand", "implant_quantity", "invoice_file_name", "invoice_content_type", "invoice_file_size", "invoice_updated_at", "invoice2_file_name", "invoice2_content_type", "invoice2_file_size", "invoice2_updated_at", "number", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24) RETURNING "id"
Recently I clone my app from heroku and I pull all the database from there then when I added a new migration with new column I got the error
def self.up
change_table :cases do |t|
t.attachment :invoice2
t.attachment :invoice3
t.attachment :invoice4
t.attachment :invoice5
t.timestamps
end
end
def self.down
remove_attachment :cases, :invoice2
remove_attachment :cases, :invoice3
remove_attachment :cases, :invoice4
remove_attachment :cases, :invoice5
end
in my schema
create_table "cases", force: :cascade do |t|
t.string "pt_first_name"
t.string "pt_last_name"
t.date "date_received"
t.date "due_date"
t.string "shade"
t.string "mould"
t.string "upper_lower"
t.integer "user_id"
t.string "invoice_file_name"
t.string "invoice_content_type"
t.integer "invoice_file_size", limit: 8
t.datetime "invoice_updated_at"
t.string "implant_brand"
t.string "implant_quantity"
t.integer "number"
t.boolean "finished"
t.boolean "ship"
t.boolean "outsourced"
t.string "invoice2_file_name"
t.string "invoice2_content_type"
t.integer "invoice2_file_size", limit: 8
t.datetime "invoice2_updated_at"
t.string "invoice3_file_name"
t.string "invoice3_content_type"
t.integer "invoice3_file_size", limit: 8
t.datetime "invoice3_updated_at"
t.string "invoice4_file_name"
t.string "invoice4_content_type"
t.integer "invoice4_file_size", limit: 8
t.datetime "invoice4_updated_at"
t.string "invoice5_file_name"
t.string "invoice5_content_type"
t.integer "invoice5_file_size", limit: 8
t.datetime "invoice5_updated_at"
t.datetime "created_at"
t.datetime "updated_at"
end
Let me know if there more information do you need! Thanks in advance.
That migration seems like it creates a null: false constraint. Presumably the existing rows in your DB do not have any values there. To fix this you would have to be able to pass an option to the migration to tell it that you want the column to be nullable.
Are you using Paperclip? Paperclip has been deprecated in favor of activestorage, but one of its open bugs was that the t.attachment migration didn’t pass on options correctly, so even if you did use a null: true option, it might not work. In this case the solution would be to move to active storage, or use a fork of paperclip that is up to date (there is one recommended in that paperclip issue.

Rails 5.2 ActiveStorage with UUIDs on Postgresql

We have our app using uuids are primary keys, on a Postgresql Database. (Standard setup described here).
We integrated ActiveStorage following the process described here. A standard setup using rails active_storage:install and migrated using rails db:migrate.
We have a model & corresponding controller as follows:
# Model
class Message < ApplicationRecord
has_one_attached :image
def filename
image&.attachment&.blob&.filename
end
end
# Controller
class MessagesController < ApplicationController
def create
message = Message.create!(message_params)
redirect_to message
end
private
def message_params
params.require(:message).permit(:title, :content, :image)
end
end
We observed that the first few sets of image were correctly associated with the model instances, but then we used to get random images for model instance, or got no image at all. Every time, we restart the server, we get first few images right, but then it was unpredictable.
Unsure, of what's going wrong, we debugged in rails console:
params[:image]
=> #<ActionDispatch::Http::UploadedFile:0x007fcf2fa97b70 #tempfile=#<Tempfile:/var/folders/dt/05ncjr6s52ggc4bk6fs521qw0000gn/T/RackMultipart20180726-8503-vg36kz.pdf>, #original_filename="sample.pdf", #content_type="application/pdf", #headers="Content-Disposition: form-data; name=\"file\"; filename=\"sample.pdf\"\r\nContent-Type: application/pdf\r\n">
On saving the instance and retrieving file name we got a random file, we uploaded previously.
#message = Message.new(message_params)
#message.filename
=> #<ActiveStorage::Filename:0x007fcf32cfd9e8 #filename="sample.pdf">
#message.save
#message.filename
=> #<ActiveStorage::Filename:0x007f82f2ad4ef0 #filename="OtherSamplePdf.pdf">
Looking for an explanation for this weird behaviour, and a possible solution too.
After hours of going line by line in the activestorage source code, and running the same commands
#message = Message.new(message_params)
#message.save
again and again. We got same random results again and again. Then we went through the logs rails printed while attaching the image to message and observed the following:
S3 Storage (363.4ms) Uploaded file to key: KBKeHJARTjnsVjkgSbbii4Bz (checksum: S0GjR1EyvYYbMKh44wqlag==)
ActiveStorage::Blob Create (0.4ms) INSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["key", "KBKeHJARTjnsVjkgSbbii4Bz"], ["filename", "sample.pdf"], ["content_type", "application/pdf"], ["metadata", "{\"identified\":true}"], ["byte_size", 3028], ["checksum", "S0GjR1EyvYYbMKh44wqlag=="], ["created_at", "2018-07-26 04:54:33.029769"]]
ActiveStorage::Attachment Create (2.7ms) INSERT INTO "active_storage_attachments" ("name", "record_type", "record_id", "blob_id", "created_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "file"], ["record_type", "Message"], ["record_id", "534736"], ["blob_id", "0"], ["created_at", "2018-07-26 05:04:35.958831"]]
record_id was being set as 534736, instead of an uuid. Here's where we went wrong.
Active storage was expecting integer foreign key to our Message model, and we wanted it to use uuids instead. So we had to fix our migration, to use uuids instead of integer foreign keys.
Solution:
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
def change
create_table :active_storage_blobs, id: :uuid 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 ], unique: true
end
create_table :active_storage_attachments, id: :uuid do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false, type: :uuid
t.references :blob, null: false, type: :uuid
t.datetime :created_at, null: false
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
end
end
end
Hope this helps, someone facing similar issues. cheers!
I'm late to the party hitting this in 2020 but as anurag mentioned this is due to the active_storage_attachments DB table using a bigint for the record_id. I wasn't able to migrate all the models with ActiveStorage attachments to use UUIDs so I needed a way to support both UUIDs and bigints at the same time.
Warning: If you can avoid this (by migrating everything to UUID most likely) then I'd strongly recommend doing that, and I plan on doing that as soon as we have time.
Warnings aside, migrating the active_storage_attachments table to change the record_id column to be text does work. I had to adjust the few places in our app where we were joining against the active_storage_attachments table using record_id to cast the value to text in the join. For example I used the following code when joining to a model that had a UUID ID.
.joins("
LEFT OUTER JOIN active_storage_attachments
ON active_storage_attachments.record_id = documents.id::text
")
Hopefully this helps someone else who is stuck in the halfway state where not all ActiveStorage using models are using UUIDs or bigint IDs.
I also had this issue. My models all use UUIDs. As I had no records in ActiveStorage needing to be retained, I dropped and recreated the :active_storage_attachments and :active_storage_blobs tables. Here is my migration, in case it's of use to anyone. Using Rails 6.0.4.
def change
reversible do |dir|
dir.up do
drop_table :active_storage_attachments
drop_table :active_storage_blobs
create_table "active_storage_blobs", id: :uuid,
default: -> { "gen_random_uuid()" }, 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 ], unique: true
end
create_table "active_storage_attachments", id: :uuid,
default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false, type: :uuid
t.references :blob, null: false, type: :uuid
t.datetime :created_at, null: false
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
t.foreign_key :active_storage_blobs, column: :blob_id
end
end
dir.down do
drop_table :active_storage_attachments
drop_table :active_storage_blobs
# original tables generated by rails
create_table :active_storage_blobs 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 ], unique: true
end
create_table :active_storage_attachments do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false
t.references :blob, null: false
t.datetime :created_at, null: false
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
t.foreign_key :active_storage_blobs, column: :blob_id
end
end
end
end

why PG::UniqueViolation: ERROR: duplicate key value violates unique constraint?

I have a model Post and each time a post is created I want a new instance of Moderation to be created at the same time.
So in post.rb I use the callback after_save :create_moderation
Then write a private method :
...
include Reportable
after_save :create_moderation
private
def create_moderation
self.create_moderation!(blog: Blog.first)
end
But when a proposal is created I get this error :
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "moderations_reportable" DETAIL: Key (reportable_type, reportable_id)=(Post, 25) already exists. : INSERT INTO "moderations" ("blog_id", "reportable_type", "reportable_id", "created_at", "updated_at", "blog_type") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
In reportable.rb I have :
has_one :moderation, as: :reportable, foreign_key: "reportable_id", foreign_type: "reportable_type", class_name: "Moderation"
Then few other methods for reportable object.
Note that this issue doesn't happen when I run the create method in console.
EDIT
create_table "moderations", id: :serial, force: :cascade do |t|
t.string "reportable_type", null: false
t.string "reportable_id", null: false
t.integer "blog_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "blog_type", null: false
t.string "upstream_moderation", default: "unmoderate"
t.index ["blog_id", "blog_type"], name: "moderations_blog"
t.index ["reportable_type", "reportable_id"], name: "moderations_reportable", unique: true
end
create_table "posts", id: :serial, force: :cascade do |t|
t.text "title", null: false
t.text "body", null: false
t.integer "feature_id", null: false
t.integer "author_id"
t.integer "scope_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_votes_count", default: 0, null: false
t.index ["body"], name: "post_body_search"
t.index ["created_at"], name: "index_posts_on_created_at"
t.index ["author_id"], name: "index_posts_on_author_id"
t.index ["feature_id"], name: "index_posts_on_feature_id"
t.index ["proposal_votes_count"], name: "index_posts_on_post_votes_count"
t.index ["title"], name: "post_title_search"
end
To fix the issue, we have to tell ActiveRecord to look at the sequence of the table:
ActiveRecord::Base.connection.reset_pk_sequence!('table_name')
Now ActiveRecord should have the correct sequence value, and should be able to assign new id's properly.
To resolve error
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "moderations_reportable" DETAIL: Key (reportable_type, reportable_id)=(Post, 25) already exists. : INSERT INTO "moderations" ("blog_id", "reportable_type", "reportable_id", "created_at", "updated_at", "blog_type") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
As error occurred on 'moderations' table.
Run the following from rails console fix
ActiveRecord::Base.connection.reset_pk_sequence!('moderations')
Thank you
Fix pkey sequences for all database:
ActiveRecord::Base.connection.tables.each do |table_name|
ActiveRecord::Base.connection.reset_pk_sequence!(table_name)
end
Looks like you've added a unique index to your database:
t.index ["reportable_type", "reportable_id"], name: "moderations_reportable", unique: true
With a unique index you will only be able to have one record with the same reportable_type and reportable_id. It's likely that you're trying to create a moderation for a reportable that already has a moderation.
ONLY FOR THOSE WHO ARE SEEING THIS WHILE RUNNING TESTS
One possible reason is, you have some migrations that create new data-records and you ran one of the following recently.
rake db:migrate RAILS_ENV=test
or
rake db:migrate:reset RAILS_ENV=test
Solution
You need to clean/wipeout your test-DB. Run this
rake db:reset RAILS_ENV=test
This will wipeout and generate schema from schema.rb.
I think this can also resolve your problem, Add this in your staging or preprod console ( I am using Heroku for this so I added in my heroku rails console)
connection = ActiveRecord::Base.connection
connection.execute("SELECT setval(pg_get_serial_sequence('moderations', 'id'), MAX(id)) FROM moderations;")
Check out this blog for more info and how this is been generated

rails foreign key violation error key not present in table

I have two models division definition and model definition
division definition :
has_many :model_definitions, inverse_of: :division_definition, foreign_key: :division_definition_id, primary_key: :division_definition_id
ModelDefinition:
belongs_to :division_definition, inverse_of: :model_definitions, foreign_key: :division_id, primary_key: :division_id
In Db structure
def change
create_table :model_definitions do |t|
t.string :model_id , null: false, unique: true
t.string :car_model_name , null: false
t.belongs_to :division_definition , null: false
t.timestamps null: false
end
add_index :model_definitions, :division_definition_id
add_foreign_key :model_definitions, :division_definitions, on_delete: :restrict
end
divisiondefinition table
def change
create_table :division_definitions do |t|
t.integer :division_definition_id, null: false
t.string :division_name,null: false
t.timestamps null: false
end
add_index :division_definitions, :division_definition_id, unique: true
end
When i try to create model definition through division definition in console i'm getting following error
PG::ForeignKeyViolation: ERROR: insert or update on table "model_definitions" violates foreign key constraint "fk_rails_addc8b742e"
DETAIL: Key (division_definition_id)=(124) is not present in table "division_definitions".
: INSERT INTO "model_definitions" ("model_id", "car_model_name", "division_definition_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
(0.3ms) ROLLBACK
ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: insert or update on table "model_definitions" violates foreign key constraint "fk_rails_addc8b742e"
DETAIL: Key (division_definition_id)=(124) is not present in table "division_definitions".
: INSERT INTO "model_definitions" ("model_id", "car_model_name", "division_definition_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
from /home/love/.rvm/gems/ruby-2.2.0/gems/activerecord-4.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:602:in `exec_prepared'
This is what i tried,
DivisionDefinition.create(division_definition_id: '124', division_name: 'BMW')
a = DivisionDefinition.last.model_definitions.build(model_id: 'bmw1', car_model_name: 'bmw1')
a = DivisionDefinition.last.model_definitions.build(model_id: 'bmw1', car_model_name: 'bmw1')
a.save
If i remove add_foreign_key from db i am able to create model definition through divisiondefinition
what is the error i'm making in migration file?
Your ModelDefinitions class refers to :division_id which appears nowhere else in your code.

Datetime field using Rails on Postgres

I'm using Rails to make a scheduling app with Postgres. I have a model Shift with two timedate columns, start_at and end_at. The migration to create it follows:
class CreateShifts < ActiveRecord::Migration
def change
create_table :shifts do |t|
t.references :user
t.references :schedule
t.datetime :start_at
t.datetime :end_at
t.string :position
t.string :notes
t.timestamps
end
add_index :shifts, :user_id
add_index :shifts, :schedule_id
end
end
When I try to create a record I get the following error 500 output:
GError: ERROR: column "end_at" is of type timestamp without time zone but expression is of type time without time zone at character 132
HINT: You will need to rewrite or cast the expression.
: INSERT INTO "shifts" ("created_at", "end_at", "notes", "position", "schedule_id", "start_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"
I am creating a valid DateTime object before the DB save, because I've used the logger to display it and it is correct. The params look like this:
{"utf8"=>"✓",
"authenticity_token"=>"qornHMTAdikZJP/sByPIg//fFuYHHAQH3M/0R9XnP+o=",
"shift"=>{"user_id"=>"1",
"start_at(1i)"=>"2011",
"start_at(2i)"=>"11",
"start_at(3i)"=>"14",
"start_at(4i)"=>"00",
"start_at(5i)"=>"01",
"end_at(1i)"=>"2011",
"end_at(2i)"=>"11",
"end_at(3i)"=>"14",
"end_at(4i)"=>"00",
"end_at(5i)"=>"02",
"position"=>"",
"notes"=>""},
"schedule_id"=>"1"}
However, I can create a record via console by setting both fields to Time.now.
The error message is quite clear:
Your $2 in the INSERT statement is of type time instead of type timestamp (datetime)
INSERT INTO "shifts"
("created_at", "end_at", "notes", "position", "schedule_id", "start_at", "updated_at", "user_id")
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"
Emphasis mine.
You must be mixing up parameters, $2 is obviously not the one you display at the end of your posting. Or you inadvertently cast it to time before assigning. The part where you assign $2 is not visible in the question, that is where the problem occurs, most likely.
Maybe some kind of typo like in your question where you mention timedate instead of datetime?

Resources