Reputation: 355
I need to get hstore working in a rails migration. I have enabled hstore through a migration, now, I am trying to generate the correct sql to get it working but when I run db:migrate I get this error;
C:\Sites\Peoples_Profiles>rails db:migrate
rails aborted!
SyntaxError: C:/Sites/Peoples_Profiles/db/migrate/20180407073155_add_hstore_hash_to_urls.rb:4: syntax error, unexpected '\n', expecting =>
C:/Sites/Peoples_Profiles/db/migrate/20180407073155_add_hstore_hash_to_urls.rb:10: syntax error, unexpected end-of-input, expecting keyword_end
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
The migration looks like this.
class AddHstoreHashToUrls < ActiveRecord::Migration[5.0]
def self.up
change_column :users, :urls, default: {}, "hstore USING urls::hstore"
end
def self.down
change_column :users, :urls, :text
end
end
What is the correct sql to get the type set for that column and why am I get a newline error?
UPDATE My urls are getting stored like this in db
urls: {"url1"=>"", "url2"=>"", "url3"=>"", "url4"=>"", "url5"=>""}
so I think postgres is complaining because it is trying to convert this code..
So after check how rails actually brings in paramaters it looks like this
["urls", "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nurl1: http://hello\nurl2: http://jack\nurl3: http://boo\nurl4: ''\nurl5: ''\n"]
Not sure if it looks like this in the db unfortunetly but I say there is a \n in there some where causing this error. Will have to pursue this further.
... and I realise now the \n will be coming from the conversion of serializing a hash to YAML.
Upvotes: 3
Views: 516
Reputation: 434665
Presumably you started with:
serialize :urls
in your model so your hashes are being stored in the database as YAML. There is no type cast from YAML text to hstore
so your USING:
USING urls::hstore
won't work. There's no easy way to reliably parse YAML inside PostgreSQL so your best bet is to:
users.urls
column to users.yaml_urls
.urls
column with (preferably) jsonb
type but you can use hstore
if necessary. jsonb
is the future and will be better supported going forward.yaml_urls
value from the database into Ruby.h = YAML.load(yaml_from_db)
.h.to_json
) and put it back in the database.urls
NOT NULL if desired and drop the yaml_urls
column.I'd recommend using the low level pg interface for this as you don't want ActiveRecord stuff in the way, can you find such a connection in ApplicationRecord.connection.raw_connection
. I say this because you don't want data migrations interacting with models in any way and the low level interface supports placeholders so you can avoid escaping and quoting issues.
That process assumes that you don't have that much data or, equivalently, your app can be offline while you fix the database. If that's not the case then you'd need to maintain both formats (add a new jsonb
column, write to and read from both inside your model when urls
and urls=
are called) while you fix the data, and then clean up later.
Upvotes: 2
Reputation: 1
Try to change the SELF.DOWN to SELF.ANNUAL I think its will solve
Upvotes: -1