Hi I am having a postgres syntax error that I cant seem to track down when using HSTORE
ERROR:
2.0.0p247 :021 > e.save
(218.8ms) BEGIN
SQL (219.8ms) INSERT INTO "communications" ("created_at", "incoming", "properties", "type", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["created_at", Thu, 19 Sep 2013 23:49:14 EST +10:00], ["incoming", true], ["propertie
s", "{\"to\":\"First email test!\"}"], ["type", "Email"], ["updated_at", Thu, 19 Sep 2013 23:49:14 EST +10:00]]
PG::InternalError: ERROR: Syntax error near 'e' at position 13
: INSERT INTO "communications" ("created_at", "incoming", "properties", "type", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
(218.4ms) ROLLBACK
That error is from the rails console when I try to save a Email record, in my app email inherits from the Communication model and the records are stored in the "communications" table in the database.
MODELS:
class Communication < ActiveRecord::Base
belongs_to :patient
belongs_to :practice
end
and...
class Email < Communication
store_accessor :properties, :to, :cc, :bcc, :message, :subject
end
Not sure why but couple of days later maybe the DB or a server restart has fixed the problem... all good thanks for your assistance #user647622
Related
I have a Rails 7 model that uses Postgres' virtual column feature:
create_table :time_entries do |t|
# ...
t.virtual :duration, type: :interval, as: %(("to" - "from")::interval), stored: true, null: false
# ...
end
The problem is, that after I create a record via Rails create(...) these virtual column is nil:
[16] pry(main)> TimeEntry.create(from: Time.zone.now, to: 1.day.from_now)
TRANSACTION (0.3ms) BEGIN
TimeEntry Create (0.5ms) INSERT INTO "time_entries" ("from", "to", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id"
[["from", "2022-11-18 06:45:11.419000"], ["to", "2022-11-19 06:45:11.420000"], ["created_at", "2022-11-18 06:45:11.420862"], ["updated_at", "2022-11-18 06:45:11.420862"]]
TRANSACTION (0.9ms) COMMIT
=> #<TimeEntry:0x0000ffff86f1ae10
id: 13,
from: Fri, 18 Nov 2022 06:45:11.419000000 UTC +00:00,
to: Sat, 19 Nov 2022 06:45:11.420000000 UTC +00:00,
duration: nil,
created_at: Fri, 18 Nov 2022 06:45:11.420862000 UTC +00:00,
updated_at: Fri, 18 Nov 2022 06:45:11.420862000 UTC +00:00>
When you reload the model, duration is set.
I found out, that this is due to Rails only returning the id column using RETURNING "id" at the end of the INSERT INTO statement. When you execute the query in Postgres directly you can return the generated duration column directly after the insert:
app_development=# INSERT INTO "time_entries" ("from", "to", "created_at", "updated_at") VALUES ( '2022-11-18 06:34:46.889000', '2022-11-18 06:34:56.889000', '2022-11-18 06:34:46.889000', '2022-11-18 06:34:46.889000') RETURNING "duration", "id";
duration | id
----------+----
00:00:10 | 11
(1 row)
Is it possible to customize the RETURNING "id" part of the SQL query in my model, so that the instance of TimeEntry already have the duration set after I create it?
EDIT:
I found the code segment inside the Postgres Adapter and tried to monkey patch it like this:
require "active_record/connection_adapters/postgresql/database_statements"
module PostgresReturningPatch
def sql_for_insert(...)
sql, *args = super
if sql.include?(TimeEntry.table_name) && sql.ends_with?(%(RETURNING "id"))
returning_virtual_columns = TimeEntry::columns.select(&:virtual?).map do |column|
quote_column_name(column.name)
end.join(", ")
sql += ", #{returning_virtual_columns}"
end
binding.pry
[sql, *args]
end
end
ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements.module_eval do
prepend PostgresReturningPatch
end
Unfortunately, it's still nil when Rails returns the instance of my model, despite that the SQL ends now with RETURNING "id", "date", "duration".
I have a problem with nested_attributes, I have the next entities:
class Experience < ActiveRecord::Base
has_many :roles, inverse_of: :experience
end
class Role < ActiveRecord::Base
belongs_to :experience, inverse_of: :roles
end
I have the next set of parameters:
params = {"end_date"=>"02/01/2012",
"city"=>"Buenos Aires",
"state"=>"",
"country"=>"",
"title"=>nil,
"company"=>"Restorando",
"current"=>nil,
"description"=>nil,
"roles_attributes"=>
[{"id"=>558, "title"=>"System Owner", "start_date"=>"03/01/2000", "end_date"=>"02/01/2001", "description"=>"<p>I did a bunch of stuff</p>", "current"=>false},
{"id"=>561, "title"=>"Test", "description"=>nil, "current"=>nil},
{"id"=>557, "title"=>"Full Stack Developerr", "start_date"=>"01/01/2011", "end_date"=>"02/01/2012", "description"=>"<p>Full Stack Developer description</p>", "current"=>false}],
"resumes_experiences_attributes"=>[{"id"=>384, "resume_id"=>809}, {"id"=>385, "resume_id"=>3199}]}
And I want to update a rails model. So I execute:
#experience = Experience.find(some_id)
#experience.update_attributes(params)
This returns me an error
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate
key value violates unique constraint "roles_pkey"
If I see what Rails is trying to update I see the next sql statement:
UPDATE "roles" SET "start_date" = $1, "end_date" = $2, "current" = $3,
"id" = $4, "description" = $5, "title" = $6, "created_at" = $7,
"updated_at" = $8 WHERE "roles"."id" = $9 [["start_date", nil],
["end_date", nil], ["current", nil], ["id", 561], ["description",
nil], ["title", "Test"], ["created_at", "2017-06-23 10:54:10.194605"],
["updated_at", "2017-06-23 10:54:10.194605"], ["id", 558]]
Which to me is strange because it's trying to update a record id, if you see the statement you will see: "id" = $4 and the where clause WHERE "roles"."id" = $9 which is correct, but its taking two different id values.
Instead if I execute:
#experience = Experience.include(:roles).find(some_id)
#experience.update_attributes(params)
It works perfectly
The initial case also works if I enter a rails console and manually trigger it. I don't know why this is happening, of course there are more complexity in the applications and I just give you the basic data to solve it but any insight would be helpful.
I've never had this before, but somehow when I'm combining a date and a time to a concatenated datetime and store it in the db, I'm off by 2 hours. I just noticed when I started using time_ago_in_words, it's always two hours from now when I just saved something new.
Any idea how to overcome this differnece. I think this is the code that's responsible for the difference:
def create_timestamp
self.date = day.to_datetime + time.seconds_since_midnight.seconds
end
In case anyone is wondering, I'm using a seperate date & time picker on my form, so this the before_save method to create one timestamp for the user input.
Upon request, the SQL for an INSERT at 10:47 CEST, Rails app is in UTC btw:
INSERT INTO "reports" ("account_id", "description", "report_category_id", "day", "time", "user_id", "date", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id" [["account_id", 2], ["description", ""], ["report_category_id", 4], ["day", "2016-07-30"], ["time", "2000-01-01 10:47:00.000000"], ["user_id", 1], ["date", "2016-07-30 10:47:00.000000"], ["created_at", "2016-07-30 08:47:53.828175"], ["updated_at", "2016-07-30 08:47:53.828175"]]
In my rails 4.2 app I have set it as the default locale by setting it in config/application.rb:
config.i18n.default_locale = :it
I have a simple "product" model
class Product < ActiveRecord::Base
translates :name, :description
end
My need is when I18n.locale = :it the content should be written in "products" table while for all others locales the content shoud go in the "product_translations" table.
Currently what happens is the following:
if
config.i18n.default_locale = :en
content is written to the "products" table, for all different locales the content goes to the "product_translations" table.
How can I change this?
EDIT
Using the console to test globalize behaviour I found that maybe I did not understand how globalize should work.
I was expecting that the "products" table is filled with default_locale (in my case :it) and the "product_translations" table is filled with other locales (:en, :fr, :de and so on).
Instead I see that whichever the locale is, fields that are indicated as
translates :name, :description
are always written in "product_translations" and "product" table only contains those fields that are not translated (in my case uom (unit of measure).
This is the output of the console after saving a new product with :en as locale.
[18] pry(main)> en_p=Product.create(:name=>"butter",
:description => "82% min fat butter",
:uom => "kg") (0.3ms)
BEGIN
SQL (0.7ms)
INSERT INTO "products" ("uom", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"
[
["uom", "kg"],
["created_at", "2015-07-14 05:49:09.097092"],
["updated_at", "2015-07-14 05:49:09.097092"]
]
SQL (0.7ms)
INSERT INTO "product_translations" ("locale",
"name",
"description",
"product_id",
"created_at",
"updated_at")
VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
[
["locale", "en"],
["name", "butter"],
["description", "82% min fat butter"],
["product_id", 5],
["created_at", "2015-07-14 05:49:09.116683"],
["updated_at", "2015-07-14 05:49:09.116683"]
]
(15.9ms)
COMMIT
=> #<Product:0xb63d3568
id: 5,
name: "butter",
description: "82% min fat butter",
uom: "kg",
created_at: Tue, 14 Jul 2015 05:49:09 UTC +00:00,
updated_at: Tue, 14 Jul 2015 05:49:09 UTC +00:00>
[19] pry(main)> I18n.locale=:it
=> :it
[20] pry(main)> it_p=Product.create(:name=>"olio di oliva EVO",
:description => "Olio di oliva extravergine spremuto a freddo",
:uom => "kg") (0.4ms)
BEGIN
SQL (0.5ms)
INSERT INTO "products" ("uom", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"
[
["uom", "kg"],
["created_at", "2015-07-14 05:51:34.772755"],
["updated_at", "2015-07-14 05:51:34.772755"]
]
SQL (0.8ms)
INSERT INTO "product_translations" ("locale",
"name",
"description",
"product_id",
"created_at",
"updated_at")
VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
[
["locale", "it"],
["name", "olio di oliva extravergine"],
["description", "Olio di oliva extravergine ottenuto unicamente per spremitura"],
["product_id", 6],
["created_at", "2015-07-14 05:51:34.779220"],
["updated_at", "2015-07-14 05:51:34.779220"]
]
(16.1ms)
COMMIT
=> #<Product:0xb6315ce8
id: 6,
name: "olio di oliva extravergine",
description: "Olio di oliva extravergine ottenuto unicamente per spremitura",
uom: "kg",
created_at: Tue, 14 Jul 2015 05:51:34 UTC +00:00,
updated_at: Tue, 14 Jul 2015 05:51:34 UTC +00:00>
Is this the default behaviour?
Do I need to remove translatable fields from the original table?
I am using Rails 3.2.8 and Devise 2.1.2 (latest) and am baffled as to why I can create a user just fine with Ruby 1.9.2 but not with Ruby 1.9.3, using exactly the same codebase.
Rails console:
User.find_or_create_by_email('example#example.com', :password => 'example', :first_name => 'Super', :last_name => 'Admin', :terms_and_conditions => true)
The output in 1.9.3 shows ROLLBACK (see below), but I just can't seem to figure out why.
Output (partial) when using 1.9.2:
SQL (0.3ms) INSERT INTO "versions" ("created_at", "event", "item_id", "item_type", "object", "whodunnit") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["created_at", Wed, 10 Oct 2012 13:57:07 UTC +00:00], ["event", "create"], ["item_id", 20], ["item_type", "OrderType"], ["object", nil], ["whodunnit", nil]]
Currency Load (1.1ms) SELECT "currencies".* FROM "currencies" WHERE "currencies"."code" = 'USD' LIMIT 1
SQL (2.4ms) INSERT INTO ..
(continues with the next insert statement)
Output (partial) when using 1.9.3:
SQL (0.3ms) INSERT INTO "versions" ("created_at", "event", "item_id", "item_type", "object", "whodunnit") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["created_at", Wed, 10 Oct 2012 12:29:49 UTC +00:00], ["event", "create"], ["item_id", 16], ["item_type", "OrderType"], ["object", nil], ["whodunnit", nil]]
Currency Load (0.3ms) SELECT "currencies".* FROM "currencies" WHERE "currencies"."code" = 'USD' LIMIT 1
(0.1ms) ROLLBACK
=> #<User id: 4, first_name: "Super", last_name: "Admin", admin_notes: nil, email: "example#example.com", ...
(stops)
I am thinking this could be an issue with Devise but am not sure.
Would appreciate any help!
Update Oct 19:
I found out that the cause of the problem is an after_create callback in user.rb that creates a "broker" (through the broker model) where it sets commission = 9.95
From the annotation in broker.rb:
# commission :decimal(, )
And more from broker.rb:
belongs_to :user
PRICE_REGEX = /^([1-9]\d{0,20}|0)(\.\d{0,3})?$/
PRICE_ERROR_MESSAGE = "Must be a number. If you want to include decimals, please use comma as decimal separator. Periods (.) = thousand separator cannot be used."
validates :commission, :format => {:with => PRICE_REGEX, :message => PRICE_ERROR_MESSAGE }, :allow_blank => true
As written above, setting broker commission to 9.95 works fine with ruby 1.9.2 but fails with ruby 1.9.3.
When saving it through rails console in 1.9.3, I get an "ActiveRecord::RecordInvalid: Validation failed..." error. No error in 1.9.2.
If I set it to 10 instead of 9.95 it works in both 1.9.2 and 1.9.3 (broker commission is set to 10).
If I set it to 9,95 (comma, not period) the user and broker is created fine but the broker commission is set to 0.
As the validation error message says, periods (.) are not allowed so it makes sense that the validation fails, but then it would have been a bug in ruby 1.9.2 that had it work before I switched to 1.9.3.
Any good explanation would be welcome :-)
After failed save check #user.errors it may have a clue
EDIT
In your Rails console
#user = User.find_or_create_by_email('example#example.com', :password => 'example', :first_name => 'Super', :last_name => 'Admin', :terms_and_conditions => true)
#user.errors
or
#user.errors.full_messages