Rails and Heroku PGError: column does not exist - ruby-on-rails

This page I have been developing for my app has been working fine locally (using sqllite3) but when I push it to Heroku, which uses PostgreSQL I get this error:
NeighborhoodsController# (ActionView::Template::Error) "PGError: ERROR: column \"isupforconsideration\" does not exist\nLINE 1: ... \"photos\" WHERE (neighborhood = 52 AND isUpForCon...\n
From this line of code:
#photos = Photo.where(["neighborhood = ? AND isUpForConsideration = ?", #neighborhood.id, 1])
isUpForConsideration is defiantly part of the Photo column. All my migrations are up to date, and when I pull the db back locally isUpForConsideration is still there, and the app still works locally.
I've also tried:
#photos = #neighborhood.photos(:conditions => {:isUpForConsideration => 1})
and
#photos = #neighborhood.photos.where(["isUpForConsideration = 1"])
Which gives me this error:
NeighborhoodsController# (ActionView::Template::Error) "PGError: ERROR: column \"isupforconsideration\" does not exist\nLINE 1: ...tos\" WHERE (\"photos\".neighborhood = 52) AND (isUpForCon...\n
Any idea what I could be doing wrong?

Your problem is that table and column names are case sensitive in PostgreSQL. This is normally hidden by automatically converting these to all-lowercase when making queries (hence why you see the error message reporting "isupforconsideration"), but if you managed to dodge that conversion on creation (by double quoting the name, like Rails does for you when you create a table), you'll see this weirdness. You need to enclose "isUpForConsideration" in double quotes when using it in a WHERE clause to fix this.
e.g.
#photos = #neighborhood.photos.where(["\"isUpForConsideration\" = 1"])

Another way to to get this error by modifying a migration and pushing changes up to Heroku without rebuilding the table.
Caveat: You'll lose data and perhaps references, so what I'm about to explain is a bad idea unless you're certain that no references will be lost. Rails provides ways to modify tables with migrations -- create new migrations to modify tables, don't modify the migrations themselves after they're created, generally.
Having said that, you can run heroku run rake db:rollback until that table you changed pops off, and then run heroku run rake db:migrate to put it back with your changes.
In addition, you can use the taps gem to back up and restore data. Pull down the database tables, munge them the way you need and then push the tables back up with taps. I do this quite often during the prototyping phase. I'd never do that with a live app though.

Related

Error on Heroku whenever I try to change database column type

I changed a column in my database like so:
class ChangePriceToBeFloatInProducts < ActiveRecord::Migration[5.1]
def change
change_column :products, :price, :float
end
end
It works fine on my local machine, but whenever I try to run this migration on Heroku via heroku run rake db:migrate I get the following error:
StandardError: An error has occurred, this and all later migrations canceled:
PG::DatatypeMismatch: ERROR: column "price" cannot be cast automatically to type double precision
HINT: You might need to specify "USING price::double precision".
: ALTER TABLE "products" ALTER COLUMN "price" TYPE float
I've already tried to reset my database, but I'm still getting this same error.
How can I fix this?
Your error message is coming from PostgreSQL but you are developing using MySQL.
It's a very good idea to use the same database technology in development and production (as well as testing, staging, and any other environments you may have). This will minimize surprises when you move from one environment to the next, e.g. when you deploy your code to Heroku.
I recommend one of the following two courses of action:
Switch to PostgreSQL on your development machine.
This will probably cause your migration to fail locally, but that's a good thing! Now you can troubleshoot and fix the error in development, which is much better than dealing with issues that pop up in production.
In this case the problem is linked to the current type of your price column. PostgreSQL isn't able to convert that data type to a float by itself and needs some help from you.
Switch to MySQL on Heroku.
Heroku uses PostgreSQL out of the box, but it also supports many other data stores. Pick one of the MySQL providers and use it instead of PostgreSQL.
In both cases, try to match the version number of the database provider.
Either of these will work, but my strong preference would be the first option. MySQL is a bit too fast and loose with data types for my liking. If you choose to go with MySQL take a close look at your data before and after running your migration locally to make sure it is doing "the right thing".
Edit: It looks like you're actually using SQLite on your local machine. That won't work on Heroku due to its ephemeral filesystem. You'll have to use a client-server database on Heroku, and I strongly recommend using the same one on your local development machine.
I believe if you want to change that column type Postgres wants you to tell it what to do with any values currently in the column. The hint is pointing you to:
change_column :products, :price, 'float USING CAST(price AS float)'
If the Rails adapter for Postgres doesn't like 'float' you might have to change to wording of the type.
If you're on development environment, I'd drop the column:
remove_column :products, :price
And adding it again:
add_column :products, :price, :float
Then running migration should pass without any problems
Unless you have data on it then you'll have to change using expressions

Rails Seed Data with Association Heroku Error

I'm trying to load some seed data into an app with heroku. I'm more looking just to insert a bunch of seed (sample) data into my app so my client can see it with a lot of objects. (Imagine a demo e-commerce app - I want to be able to show a couple dozen sample products without manually entering them in)
My seed data works fine in development but in production, the one HMBT association causes the below error:
WARNING: Rails was not able to disable referential integrity.
This is most likely caused due to missing permissions.
Rails needs superuser privileges to disable referential integrity.
Heroku documentation said this this so I tried a conditional to remove the referential integrity on production in my seeds file(see below), but now seeds won't run. It just does this:
Running rake db:seed on ⬢ app... up, run.1225 (Free)
ActiveRecord::SchemaMigration Load (1.7ms) SELECT "schema_migrations".* FROM "schema_migrations"
Here's my seeds file below:
if Rails.env.development?
ActiveRecord::Base.connection.disable_referential_integrity do
end
1.upto(14) do |n|
pic_one = File.open(File.join(Rails.root,'app/assets/images/file1.jpg'))
pic_two = File.open(File.join(Rails.root,'app/assets/images/carpet_2/file2.jpg'))
image = PicAttachment.create!([
{picture: pic_one, w_dream_id: "#{n}"},
{picture: pic_two, w_dream_id: "#{n}"},
])
rug = Product.create!(
pic_attachments: image
end
if Rails.env.development?
end
end
Does anyone where I'm going wrong?
The link you posted states that referential integrity cannot be removed in Heroku. It suggests considering using another test data scaffolding tool (like FactoryGirl or Fabrication Gem)
Anyway, your code does nothing if the environment is not development. All code is inside the if Rails.env.development?. The first end corresponds to the do. The indentation is wrong. Your code is in fact:
if Rails.env.development?
ActiveRecord::Base.connection.disable_referential_integrity do
end
1.upto(14) do |n|
pic_one = File.open(File.join(Rails.root,'app/assets/images/file1.jpg'))
pic_two = File.open(File.join(Rails.root,'app/assets/images/carpet_2/file2.jpg'))
image = PicAttachment.create!([
{picture: pic_one, w_dream_id: "#{n}"},
{picture: pic_two, w_dream_id: "#{n}"},
])
rug = Product.create!(
pic_attachments: image
if Rails.env.development?
end
end
Ultimately I took this answer, which was already in my code to ensure associations work in development.
For development, this is needed:
ActiveRecord::Base.connection.disable_referential_integrity do
For production:
the disable_referential_integrity isn't allowed in heroku and the problem is the associated model (Pic_Attachment) gets created before the model object it belongs to, hence an error gets thrown because it needs an object to belong. What worked for me was to delete the disable_referential_integrity from the seeds file AND comment out the belongs_to line in the associated model (PicAttachment), then commit/push your changes and it works. (Add these lines back in afterwards so your development works)
I hope this helps someone. Took me a few days of work here.

Rails migration to clear contents of a database table?

The (occasionally very large) output of some JSON-calls get written into my database to speed things up a little; the app gets the JSON-output pre-rendered from the database.
Every once there's a little change in the content so the output would have been different. I'm looking for a rails migration that I could just include in my deployment for clearing out the specific table storing my JSON code.
You can put that in your migration. Warning, this will delete all data from the table !
Model.connection.execute('DELETE FROM table_name');
Or altenatively you could run some code every day (crontab) to delete everything that is X months old :
def self.delete_old_stuff
month = 3
Model.where("updated_at < ?" , month.months.ago).each{|c| c.destroy}
end
You can call that through the runner command of rails or integrate that a in rake task... I use a similar method to clear old basket in a small ecommerce app.

Rails PostgreSQL array can't iterate

I wrote a helper method for my controller to iterate through an attribute, being represented as an array using PostgreSQL.
def format_cf array
nums = ""
array.each { |c| nums += "#{c}, " }
unless nums.blank?
nums.chop!.chop!
end
nums
end
This way, I don't get the messy {} chars in my view. I'm implementing an empty value for this attribute as the string '{}', meaning that's what I set the default value to in my migration. This hasn't been a problem for my development environment, as it interprets that as an empty array. However, now in production, this helper method is throwing an error saying
ActionView::Template::Error (undefined method `each' for "{}":String)
Is my implementation wrong here, or can anyone think of some obscure setting I may have overlooked when comparing my development.rb and production.rb?
EDIT: 2013-04-11 9:00
I'm currently deploying using capistrano with unicorn and nginx
I'm going to guess you may have run into this bug as well, if you're using rails 4 https://github.com/rails/rails/issues/10432. Basically there's a bug in the Migrations system that turns :string, array: true into a normal :string directive. The joys of using edge stuff huh.
I gues you used taps to deploy tour database on heroku with
heroku db:push
Problem is that taps doesn't support Postgres array, and it ends up casting the column as a string. There are many workaround for that.
The one I used was to open a console on heroku
heroku run console
Then get a connection to the database
User.connection # or any of your models
And then execute raw sql with the connection#execute method in order to create a backup column, delete the current string column and recreate it as an array.
You'll probably find it more useful to use the import/export advised by heroku
And if you're not using heroku, then I' completely wrong, and I have no idea what your problem is :)

Rails 3 - Foreign Keys - Strings vs Symbols

I am in the process of learning Rails and I've ran into an interesting problem tonight.
I was creating a migration that would require an index on the foreign key:
Whenever I would run 'bundle exec rake db:migrate', I would receive this console error:
It looks as if it was trying to create the index before it was creating the reference.
The reason I believe this is because when I change the "subject" reference to a symbol:
The migration then suddenly works as expected!
This may just be the fact that I'm a total newby, but are symbols actually processed faster by Ruby than strings are?
Just curious - thanks!
This isn't a "faster" problem, or a problem of speed. The migrations are executed one line at a time, in order. The way you had it specified before simply didn't create the column correctly, hence when it got to the line where you create the index, the names didn't match up.
My guess is, with the string version it created the column name exactly as you spelled it, "subject" as opposed to subject_id when you use a symbol. Either way, you definitely had a name mismatch between when the column was created, and when the index was being built.
Always use symbols for this in your migrations, and you should be fine. Always check your schema.rb file, or browse the database using a GUI tool, after a migration to make sure the columns got created the way you expect, and with the data types you think they are, and you should be good.

Resources