I'm considering paying the $50/ mo for a production database so I can use PostGIS with my rails 4 app. My issue is that I would like to continue developing with a 'staging' environment, but can't yet justify paying for two production databases. Staging is obviously just a clone of production, so just pointing both apps to the same DB url (post) would likely cause some major headaches.
Is there any way to partition the database, or another strategy you'd recommend?
Initial answer from heroku support is no, but I'm hoping there's a scrappy workaround.
Thanks!
First off, I would highly suggest just paying the extra $50/mo. For that, you get all kinds of cool stuff like forking and pipelines, as well as the fact that this is kind of hacky. I honestly don't know if this might end up wiping your production data when you clear the staging database. Please make backups before trying this.
I'll view this answer as an answer to a technical challenge rather than a business decision. Without further ado,
Setting up multiple environments on the same database with Heroku Postgres schemas
First, I deleted the existing dev database and added a production database to my production app.
heroku addons:add heroku-postgresql:crane
> Adding heroku-postgresql:crane on test-shared-app... done, v# ($50/mo)
> Attached as HEROKU_POSTGRESQL_RED_URL
This attached a database under the RED color, so replace HEROKU_POSTGRESQL_RED_URL with the appropriate color for your app.
This attaches a database to the production app, but we need to connect to the same app for staging. First, create the staging schema
heroku run "bundle exec rails runner 'ActiveRecord::Base.connection.execute(%q{CREATE SCHEMA staging})'"
Next, create the staging app. See Managing Multiple Environments for an App for more information.
heroku create --remote staging test-shared-app-staging
heroku config:set RACK_ENV=staging RAILS_ENV=staging --remote staging
Then, copy the environment data from your existing app. Add ?schema_search_path=staging to the end of the URL.
heroku config --remote heroku --shell
# make note of your database URLs
heroku config:set --remote staging \
DATABASE_URL=postgres://...?schema_search_path=staging \
HEROKU_POSTGRESQL_RED_URL=postgres://...?schema_search_path=staging
And push to staging
git push staging master
Now, run migrations on staging
heroku run --remote staging bundle exec rake db:migrate
And try it out.
My "app" is running at http://test-shared-app.herokuapp.com/posts and http://test-shared-app-staging.herokuapp.com/posts. You can see the source at https://github.com/benmanns/heroku-shared-app.
If I were you, I would use production DB until the right moment (start making money or getting more users, etc). I would replicate all the tables in production DB and give the new tables new names by prepending something like "stag_{original_table_name}. So, you would have two different sets of the same tables. In your models, make them use the new table on staging environment:
class Foo < ActiveRecord::Base
self.table_name = "staging_#{self.class.name}" if Rails.env.staging?
I am pretty cheap... and this may be an ugly solution in the eyes of the true Rails masters.
Heroku Schemas is another approach to this; it's a Heroku plugin that basically lets you run a single command to apply Benjamin Manns's solution of multiple schemas.
Related
The Heroku documentation at https://devcenter.heroku.com/articles/deploying-to-a-custom-rails-environment says I shouldn't use a staging.rb file to define my staging environment.
It may be tempting to create another custom environment such as “staging” and create a config/environments/staging.rb and deploy to a Heroku app with RAILS_ENV=staging.
This is not a good practice. Instead we recommend always running in production mode and modifying any behavior by setting your config vars.
I think this is terrible advice and conflicts with well-established Rails best practice. However, I'm not here to argue about best practices. I'm here to ask:
Are there any reasons not to use RAILS_ENV=staging on Heroku?
Is there anything that will break if I create a staging.rb file and set the xxx_ENV config vars like this?
heroku config:add RACK_ENV=staging --remote staging
heroku config:add RAILS_ENV=staging --remote staging
No, there isn't anything that will break if you do this.
However, I do think that Heroku is right here (note that I work at Heroku).
It introduces possible differences between your staging and production environments, when the only thing that changes between them should be configuration variables.
Heroku already provides a secure mean of setting configuration variables, with the config:set command.
Using 2 config files means you have to maintain the same configuration twice, and possible can have issues because you updated the configuration correctly in staging, but incorrectly in production.
As a side note, RACK_ENV should only ever have 3 values: production, development and none. See https://www.hezmatt.org/~mpalmer/blog/2013/10/13/rack_env-its-not-for-you.html
You'll get some warnings from Heroku when you deploy, but I can confirm I did run staging apps, with RAILS_ENV=staging, on Heroku. As long as you set the correct environment variables and Gemfile groups, it should just work.
My guess is that the reason they advise not to use custom environments is that they have some operational tooling that assumes your Rails app runs in production environment, but so far I didn't run into issues.
I'm new to rails, and I accidentally ran rails db:rollback command in a development.
Next I did rails db:migrate:up VERSION=XXXX to change status of the file I rolled back from down to up.
The migration file was about images. However my images were gone in a development mode due to rollback, files status the same as before I ran rails db:rollback.
In this case, if I pushed this to remote repository, and it's merged in production, the images already there will be gone as well as mine in development?
When add_column method in migration is run you just add column in migration so it will run for production & development environment. Now you added images through localhost to your application and stored in database. So those will be stored to database regardless migration.
Rollback will remove column running remove_column so it will hamper your development as removing column will make you loose all data inside column of table. So on production it does not deal same.
Images are getting pushed to production database or remote repository, it is just to add or remove column only so rollback will affect only your local/development
Unless you're doing something wacky in your migrations, any goofs like this you make to your development database will not effect production. That's why dev and prod databases are separate.
The general problem of "is it safe to push to production" can be mitigated by adding a staging server which runs in the production Rails environment, but is used for additional manual testing of new features. Once everything checks out in staging then push to production. Many services provide a "pipeline" to do this for you, for example Heroku Pipelines.
I have some sort of snafu that happened where an intern accidentally uploaded a bit of code to our staging site and then cancelled. Now, there is a page on the staging site that requires a migration that doesn't exist on the staging site.
I'm relatively new to this as well and I'm wondering what the best way to add a migration for that missing column directly to the staging site. Is it
Pull the code, add the migration, push the code (which changes the
staging from the dev, as the dev has the master.
Generate the migration in some other way in heroku directly?
I honestly don't even know if the way we think this error happened is actually the truth. I just have to fix it.
If your migration existed you can rollback on directly on heroku in activity onglet.
or
Pull your repo
Add your migration
Push it on heroku
Run heroku run rake db:migrate --app your_staging_app
My goal is to have 2 databases and 2 deployments of rails on the same server. I want to have the regular production server using the production database. Then I want to be able to deploy to a different web address that will use a different database. My goal is to be able to push the backup first and make sure all the migrations etc. work in the full environment. I would then push it to the main server.
The issue I seem to run into is that the database.ml file only lists the 3 database types. The passenger environment will also assume that its running in production and would migrate the main MySQL database even if I deploy the code to a different directory. Whats the best way around this? Was wondering if it is simple or if it involves setting lots of variables in lots of places? Any suggestions would be great!
You can add other database types to database.yml as you see fit.
staging:
adapter: postgresql
host: mydb_host
database: mydb_staging
etc...
You can copy config/environments/production.rb to config/environments/staging.rb and leave it as is so the two environments are exactly the same, or tweak staging.rb as you see fit.
Now you have a staging environment! Use it where appropriate, e.g.:
rake RAILS_ENV=staging db:migrate
I am not a passenger expert, but know that my shop has both staging and production instances of apps running on the same server under passenger, so it can be done. Google can probably instruct you better on configuring that than I can.
I've setup my app to run on Heroku with a staging and production environment as according to their documents. http://devcenter.heroku.com/articles/multiple-environments
It seems pretty straightforward to manage with the staging app, push entire deployments or new branches up to test in staging. What I wonder is how to manage the production version.
How do I keep my production up and running when deploying new code? Do I pull in the changes from staging or do I redeploy the entire app with the changes merged in?
Secondly, how do I manage and keep my database intact during all of this? I'm used to running locally where if you do a new deploy and a new rake :db:migrate, you lose all your database data. How is this done in production to not lose your records?
Thanks you and ANY other tips regarding heroku management is welcome.
Typically, you make changes locally, including migrations or whatever. Before pushing your changes to your production app, push changes to your staging app to double-check things are okay.
If you added migrations in your changes, be sure to run heroku run rake db:migrate to migrate your staging database. Running rake db:migrate should not destroy any data so long as your migration is proper - i.e. no weird tampering with data, just the standard addition/renaming/etc. of columns or introducing new tables. (Obviously if you drop a table in a migration it'll be gone.)
Then, if everything is okay with your staging app, push changes to your production, and again run heroku run rake db:migrate if you had any new migrations. If things are not okay, run heroku help to get a list of commands you can use - particularly ones with regard to releases so you can revert back to a previous release. Also heroku logs is really useful, and heroku console (actual command might be slightly different), though when you start a console, be really careful not to tamper with data too much.
With Heroku, there's no deploy command needed - right when you git push, your updated code is there. No "cap deploy" with capistrano, if you've used that before.
Hope this helps.