Trouble adding st_point column with activerecord-postgis-adapter - ruby-on-rails

This is a pretty verbatim copy of what I wrote on the project github. Forgive me for cross posting but I was hoping someone here had come across this error:
undefined method `st_point' for #
<ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition:0x0055cdd8f278e8>
This is my Gemfile lock:
activerecord (4.2.7.1)
activerecord-postgis-adapter (3.1.4)
and the migration:
class CreateLocations < ActiveRecord::Migration
def change
enable_extension "postgis"
create_table :locations do |t|
t.st_point :geom, geographic: true, srid: 4326, dimension: 2
t.timestamps
end
end
end
What's wierd is that this works in development mode. It's just when I run the migrations for the test environment that it fails.
After rake db:create RAILS_ENV=test, I have conntected to the test database with psql and run CREATE EXTENSION postgis;.
tl;dr
t.st_point in the migration is undefined, only in the test environment.

The error was "postgres" instead of "postgis" in the ENV["DATABASE_URL"]
That it what others suggested on the thread. I was being stubborn by not checking for this, but it turns out to be the correct cause.

Related

schema.rb doesnt include add_index method after migration using postgresql

So I was trying to create a database index on the email column of a Users model, but I must be doing something wrong, since after I do the migration I go and check on the schema.rb file to see if the add_index method is included and nothing shows up. I am using postgresql, by the way. So here is what I did...
I created the migration
rails generate migration add_index_to_users_email
After that, I edited and saved the db/migrate/20140911192804_add_index_to_users_email.rb file with the following code for indexing:
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end
After that I ran on the console
bundle exec rake db:migrate
And when I went to check on the schema.rb file to see if the add_index method was included, I found that it wasnt there. Here is what my schema.rb looked like
ActiveRecord::Schema.define(version: 20140911192804) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
end
I tried to run rake db:rollback to run again db:migrate and see if some "magic" occurred but I wasnt even able to rollback, getting this error message:
== AddIndexToUsersEmail: reverting ===========================================
-- remove_index(:users, {:unique=>true, :column=>:email})
←[1m←[35m (0.0ms)←[0m ROLLBACK
rake aborted!
An error has occurred, this and all later migrations canceled:
Index name 'index_users_on_email' on table 'users' does not existC:in `migrate'
Tasks: TOP => db:rollback
I'm pretty lost... something that i found interesting was that in the schema.rb file this line
ActiveRecord::Schema.define(version: 20140911192804) do
had the same timestamp as the migration file for the add_index db/migrate/20140911192804_add_index_to_users_email.rb
So there was some sort of update on the schema.rb file during the migration but not what I was expecting to occur.
I don't even know where to start :D so I hope someone a bit more experienced can give me a hint.
Thanks so much!
After hours of trial and error I could finally find a solution!
For some reason beyond my understanding, the migration didnt add the add_index method to my schema.rb, however, when I tried to rollback, it was looking for an index in the users table that didnt exist, so it kept aborting the rollback.
I assumed that the info about the index that it had to look for in the table was in the migration file. So I deleted the content of the migration file leaving it like this:
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
end
end
I was finally able to rollback.
Then I typed again the content inside the AddIndexToUsersEmail migration file
class AddIndexToUsersEmail < ActiveRecord::Migration
def change
add_index :users, :email, unique: true
end
end
I ran again bundle exec rake db:migrate
and it worked! :D
Thanks a lot to everyone who took their time to read this issue!
I just had the same problem and found why !!!
You (we) used the migrate command before saving the migrate file !! So the migration was passed with nothing inside. Just a change method with no instructions.
And if after you try to rollback and the migration file have been saved since. The add_index instruction is in so it can't rollback.
I hope i am clear enough.

What to do after a failed heroku db:rollback

I'm at the very beginning stages of learning rails using heroku as deployment tool. I ran into a bit of problem today, which is now fixed, but I was wondering if there's a proper/better way to do what I did.
My problem was as follows: I wrote a migration file that created a table with some indices (using add_index). The code would look like this:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :username
...
end
add_index :users, :username, :unique => true
end
def self.down
drop_table(:users)
remove_index :users, :username
end
end
heroku run rake db:migrate ran fine but heroku run rake db:rollback failed because (I assume) remove_index was trying to delete an index from a column that had already been erased.
So I then added a self.down method to my migration file (removing the indices before dropping the table). Afterwards, heroku run rake db:migrate didn't do anything, and heroku run rake db:rollback is stuck at the same error as before. Resetting the database or dropping the table didn't work either. I ended up removing the add_index lines in my migration before the rollback finally works.
... and unfortunately I no longer have any idea why db:rollback failed. The error message was 'index_users_on_username' on table 'users' does not exist', so my guess is that I did something stupid like modifying the database or modified the migration file before doing a rollback. Or could it be because I am mixing change and down method in the same migration file?
Anyway, my main question is, if a db:rollback fails, what then?
Some options in my head:
Fix the migration file until the rollback works
Fix the database manually until the rollback works
Fix the database manually and ignore the migration completely (dunno how to do this)
this)
???

PostgreSQL point type in Rails migration

I want to use the point type which there's in PostgreSQL. I've done:
rails g model Test point:point
The resulting migration is:
class CreateTests < ActiveRecord::Migration
def change
create_table :tests do |t|
t.point :point
t.timestamps
end
end
end
When I run:
rake db:migrate
The result is:
== CreateTests: migrating ====================================================
-- create_table(:tests)
rake aborted!
An error has occurred, this and all later migrations canceled:
undefined method `point' for #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::TableDefinition:0x000000038991a0>/home/i/Dropbox/programming/ruby/rails_pg_for_tests/db/migrate/20140306151700_create_tests.rb:4:in `block in change'
/home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/connection_adapters/abstract/schema_statements.rb:184:in `create_table'
/home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/migration.rb:625:in `block in method_missing'
/home/i/.rvm/gems/ruby-1.9.3-p448/gems/activerecord-4.0.2/lib/active_record/migration.rb:597:in `block in say_with_time'
...
May be I need to install PostGIS, but I don't understand what for, if I have point type in PostgreSQL. And I only need to store latitude and longitude without any other options.
How can I use this point type or what is better to use in this case?
Thank you.
You can specify the data type as a string
t.column 'point', 'point'
Rails have support for point for several years. The test cases have been there since rails 4.2 beta.
If you are using rails 4.2 or later. you should not get that error. I have not tested it on 4.2 beta yet. I only test it on rails 5.2 and it works without any additional gem.
https://github.com/rails/rails/blob/24adc20ace69ec0fcf317e0a8d91d112478ba015/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
Usage:
Migration
class CreateAddresses < ActiveRecord::Migration[5.2]
def change
create_table :addresses do |t|
t.point :coordinate
end
end
end
Create a new record
Address.create coordinate: ActiveRecord::Point.new(1, 1)
You receive undefined method 'point' for #<ActiveRecord:... error on migration code
t.point :point
because point method does not exist in ActiveRecord.
ActiveRecord natively supports following data types,
:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp,
:time, :date, :binary, :boolean
See the official documentation of ActiveRecord for the same.
As suggested by #bridiver, you could choose to specify a type other than the supported datatypes of ActiveRecord(as listed above) with t.column :point, 'point' BUT as quoted in ActiveRecord documentation
this will not be database agnostic and should usually be avoided.
UPDATE
I would recommend utilizing the benefits of activerecord-postgis-adapter gem, as suggested by #euricovidal. It is a geospatial extension for pgsql and it acts as a wrapper around the PostGIS query functions and allows you to write geo-aware migrations.
It will allow you to create a point type and using this your current syntax should work.
Refer PostGIS ActiveRecord Adapter: Creating Spatial Tables for example. You would also need to update the adapter to postgis in the database.yml file for this to work.
if you are using activerecord-postgis-adapter you need change adapter on database.yml to postgis.
https://github.com/dazuma/activerecord-postgis-adapter#installation-and-configuration
You most likely need to edit your config\database.yml to reference postgis as your database adapter
default: &default
adapter: postgis
encoding: unicode
pool: 5
timeout: 5000
host: localhost
development:
<<: *default
database: learning_rails
username: brentpayne
password:
You might also want to edit your migration to specify the :point as geographic so you can calculate distances.
t.point :point, :geographic => true
But the error you are having is identical to mine when I left my adapter set to postgresql. Changing it to postgis fixed my issues.
Reference: https://github.com/rgeo/activerecord-postgis-adapter#installation-and-configuration
If you install georuby the point datatype becomes available.
Gemfile
gem 'pg'
gem 'georuby'
In a migration
def change
create_table :space_table do |t|
t.point :location
t.timestamps
end
end
You can save a point with model_object.location = [-33.233, 123.123]

Why record does not go into rails test database

class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps
end
# Create sample User
User.create :name => "TestUser"
end
end
When run rake db:create and rake db:migrate command
In development database it creates sample user but not in test database. I want this user in test database also. any reason?
Also tried rake db:migrate RAILS_ENV=test.
First you should run the following command rake db:test:prepare in order to "prepare" the test database.
Finally, I recommend using the following file db/seeds.rb if you wish to add new records in your database.
In the db/seeds.rb file:
User.create(name: "TestUser")
Run:
rake db:seed
rake db:seed RAILS_ENV=test # for test env
If you're looking to test a user why not create a fixture or use rspec for testing something like this? The above code is bad practice. I would do something like this
migration file.
def self.up
create_table :users do |t|
t.string :name
t.timestamps
end
end
Depending on your testing stack I would setup a fixture like so(yml fixture)
david:
name: David Smith
You could also use rspec with factory girl which makes testing alot easier in rails.

rails migration version issue: any new migration not working

From this morning, I am facing weird issues with Rails devise. Following is output of my ls and rake db version command.
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$ ls -1
20120110083934_devise_create_users.rb
20120110090514_create_posts.rb
20120110090845_add_user_id_to_post.rb
20120203035323_add_confirmable_to_devise.rb
20120203035323_add_confirmable_to_devise.rb~
20120203043601_add_lockable_to_devise.rb
20120203043601_add_lockable_to_devise.rb~
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$ rake db:version
(in /home/hrishikesh/git-public/personaldiary)
DEPRECATION WARNING: require "activerecord" is deprecated and will be removed in Rails 3. Use require "active_record" instead. (called from /usr/lib/ruby/vendor_ruby/activerecord.rb:2)
Current version: 20120203034555
hrishikesh#hrishikesh-ubuntu:~/git-public/personaldiary/db/migrate$
If I try to add any new migrations, rake db:migrate throws error that tells me that some column already exists, and fails.
My failing migration code is here:
class AddConfirmableToDevise < ActiveRecord::Migration
def change
change_table(:users) do |t|
t.confirmable
end
add_index :users, :confirmation_token, :unique => true
end
end
I specifically do not want to use up and down methods because of this
Please help.
After spending hours to find solution, I decided to give up and ran
rake db:migrate:reset
And it worked, only thing is my data was lost, which was not that big deal at this point.
Thank you everyone for attempting to solve this.

Resources