How to run migrations of another app from main app - migration

I am following umbrella apps structure in my project. and I am writing access layer app which doesn't have separate repo but requires to have certain tables and relations migrated for it to work. I dont wanna create separate repo for it and make it complex to maintain configs etc.
I have tried following two approaches
defmodule Data.Repo.Migrations.CreateActions do
use Ecto.Migration
def change do
# First approach
opts = []
file_path = ExAcl.SeedHelper.priv_path_for("20181129092126_create_actions.exs", app: :acl)
Ecto.Migrator.run(Data.Repo, file_path, :up, opts)
{:ok, _} = Application.ensure_all_started(:acl)
# Second approach
Ecto.Migrator.up(HaiData.Repo, 20181129092126, ExAcl.Repo.Migrations.CreateActions)
end
end
But It doesn't run migrations in another app.
Maybe I am not going in right direction. I am not sure what is the best way to run migration in another app
Goal: run migrations in acl app via main data app.

If you try to run a migration via Ecto.Migrator.run from inside another migration, then you will most likely run into database locks, because Ecto doesn't allow you to run migrations concurrently.
If you want to use this approach, then you can do this:
def change do
file_path = ExAcl.SeedHelper.priv_path_for("20181129092126_create_actions.exs", app: :acl)
Code.require_file(file_path)
ModuleInTheMigrationFile.change()
end
But I am not sure how maintainable this would be in the long term. If there are other migrations, then you would have to explicitly require and invoke each migration one by one. And then what happens for new migrations in the future? Therefore I propose one of:
If you want to do execute only one migration and only once, simply copy the migration file to your migrations folder
If the two migrations folders are evolving side by side and you would like to automatically run migrations from both directories, you can invoke ecto.migrate twice:
mix ecto.migrate --migrations-path priv/repo/migrations
mix ecto.migrate --migrations-path other/app/priv/repo/migrations
If the two migrations folders are evolving side by side and you would like to manually run migrations from both directories, you can copy the migrations from one directory to the other and keep only one directory as source of truth

Related

Do I use Snapshot file, migration file or data annotations in my EF Core to update database?

I'm trying to understand the different types of migration paths we can choose when developing an ASP.NET Core 1.0 application with EF Core. When I created my first Core application I noticed it generated a ApplicationDbContextModelSnapshot class that uses a ModelBuilder to build the model.
Then I read that if I need to add a table to the database, I need to create the new model and run the command line to generate the migration file and update the database. Ok, I get it up to this point.
But when I do that, I notice that the ApplicationDbContextModelSnapshot class gets updated too.
1) Does that mean I cannot modify this ApplicationDbContextModelSnapshot class since it looks like it gets regenerated each time?
2) Should I use Data Annotations to build my model or should I use Fluent API which tells me to build my model in the ApplicationDbContext class? Huh? another file that builds the model?
I'm seeing three different ways of working with the database here, the snapshot class, data annotations, and fluent API. I'm confused because today, I made a mistake in my last migration file so I deleted the file, dropped the database and reran the database update.
But by doing that I got errors similar to:
The index 'IX_Transaction_GiftCardId' is dependent on column 'GiftCardId'.
ALTER TABLE ALTER COLUMN GiftCardId failed because one or more objects access this column.
So naturally I was wondering if I had to modify the ApplicationDbContextModelSnapshot class.
What is the path I should be taking when it comes to migrations or database updates because these three paths are confusing me.
I have run into this issue before when I create migrations, make model changes, create new migrations, and try to update the database. The root cause is when keys are being changed and relationships are not dropped and are not added back or do not exist.
You have two options
Easy Method
The easiest way is also the most destructive way and only possible in a dev environment.
Delete all migrations, drop the database, create new migrations and run 'update-database'.
Hard/Safest Method
This is the most time consuming method. I recommend do this in a local integration branch first, pushing it to a remote integration, and then production.
Open the migration file, ie 20160914173357_MyNewMigration.cs.
Drop all indexes in order
Drop/Add/Edit table schemas
Add all indexes back.
For either method, just be sure to test and test again.
Do not modify ApplicationDbContextModelSnapshot. It is a design-time artifact, and should only be modified in the case of a merge conflict.
To update the model, always use data annotations or the fluent API.
For more information on the EF Migrations workflow, see Code First Migrations. It's for EF6, but most of the information is still relevant.

FlywayDB ignore sub-folder in migration

I have a situation where I would like to ignore specific folders inside of where Flyway is looking for the migration files.
Example
/db/Migration
2.0-newBase.sql
/oldScripts
1.1-base.sql
1.2-foo.sql
I want to ignore everything inside of the 'oldScripts' sub folder. Is there a flag that I can set in Flyway configs like ignoreFolder=SOME_FOLDER or scanRecursive=false?
An example for why I would do this is say, I have 1000 scripts in my migration folder. If we onboard a new member, instead of having them run the migration on 1000 files, they could just run the one script (The new base) and proceed from there. The alternative would be to never sync those files in the first place, but then people would need to remember to check source control to prior migrations instead of just looking on their local drive.
This is not currently supported directly. You could put both directories at the same level in the hierarchy (without nesting them) and selectively configure flyway.locations to achieve the same thing.
Since Flyway 6.4.0 wildcards are supported in flyway.locations. Examples:
db/**/test
db/release1.*
db/release1.?
More info at https://flywaydb.org/blog/organising-your-migrations

Rails, Git and adding migrations

sometimes when working in rails, I work on several things at once using git branches
sometimes, I'd like to test new ideas by implementing them and testing how and if they work accordingly. This involves sometimes adding models and migrations.
When switching branches, however, the migrations were already migrated to the DB and they stay, causing problems later on..
Is there a way to work with several branches and each to have different migration files, and before starting to work on a branch to "soft reset" the db only to the current migration files without losing data?
Normally, in development, I need some sample data that I keep in seed.rb which enables me to recreate the db, its structure and the sample data with a rake task.
Another thing I did was to keep more than one database. I would then just manually change the entry in database.yml according to the current git branch.

How do I share a DB & data model between two Rails 3 apps?

I'm working on a project which involves aggregating data from a variety of sources so that users can search and mine it from a single front-end interface. The project breaks pretty cleanly into two components:
The cron triggered (Whenever gem) code that pulls data from various sources and POPULATES the database.
The front-end code that CONSUMES the data and presents it to the user.
I want to split the codebase into separate projects with a shared model to encourage clean separation of concerns but am not sure how best to go about that in Rails 3.
I saw this SO question about using a shared folder/submodule in SVN or Git but that doesn't seem very clean to me:
Sharing Models between two Rails Projects - using git submodules?
I come from a Java/MVN background were you would just create 3 modules (one shared and two that depend on it) and call it a day. Then with Maven you could invoke a build on the parent project and it would automatically update the shared code JAR in each dependent project.
Can the same be achieved using Rails Engines, Rake, and RubyGems? Or is there a better "rails way" to do it?
Thanks,
-James
You can keep the models in a gem/plugin. The DB configurations should remain in their respective apps, though.

Rails: Best practice for handling development data

I have the following scenario:
I'm starting development of a long project (around 6 months) and I need to have some information on the database in order to test my features. The problem is that right now, I don't have the forms to insert this information (I will in the future) but I need the information loaded on the DB, what's the best way to handle this? Specially considering that once the app is complete, I won't need this process anymore.
As an example, lets say I have tasks that need to be categorized. I've begun working on the tasks, but I need to have some categories loaded on my db already.
I'm working with Rails 3.1 btw.
Thanks in advance!
Edit
About seeds:I've been told that seeds are not the way to go if your data may vary a bit, since you'd have to delete all information and reinsert it again. Say.. I want to change or add categories, then I'd have to edit the seeds.rb file, do my modifications and then delete and reload all data...., is there another way? Or are seeds the defenitely best way to solve this problem?
So it sounds like you'll possibly be adding, changing, or deleting data along the way that will be intermingled amongst other data. So seeds.rb is out. What you need to use are migrations. That way you can search for and identify the data you want to change through a sequential process, which migrations are exactly designed for. Otherwise I think your best bet is to change the data manually through the rails console.
EDIT: A good example would be as follows.
You're using Capistrano to handle your deployment. You want to add a new Category, Toys, to your system. In a migration file then you would add Category.create(:name => "Toys") or something similar in your migration function (I forget what they call it now in Rails 3.1, I know there's only a single method though), run rake db:migrate locally, test your changes, commit them, then if it's acceptable deploy it using cap:deploy and that will run the new migration against your production database, insert the new category, and make it available for use in the deployed application.
That example aside, it really depends on your workflow. If you think that adding new data via migrations won't hose your application, then go for it. I will say that DHH (David Heinemeier Hansson) is not a fan of it, as he uses it strictly for changing the structure of the database over time. If you didn't know DHH is the creator of Rails.
EDIT 2:
A thought I just had, which would let you skip the notion of using migrations if you weren't comfortable with it. You could 100% rely on your db/seeds.rb file. When you think of "seeds.rb" you think of creating information, but this doesn't necessarily have to be the case. Rather than just blindly creating data, you can check to see if the pertinent data already exists, and if it does then modify and save it, but if it doesn't exist then just create a new record plain and simple.
db/seeds.rb
toys = Category.find_by_name("Toys")
if toys then
toys.name = "More Toys"
toys.save
else
Category.create(:name => "More Toys")
end
Run rake db:seeds and that code will run. You just need to consistently update the seeds.rb file every time you change your data, so that 1) it's searching for the right data value and 2) it's updating the correct attributes.
In the end there's no right or wrong way to do this, it's just whatever works for you and your workflow.
The place to load development data is db/seeds.rb. Since you can write arbitrary Ruby code there, you can even load your dev data from external files, for instance.
there is a file called db/seeds.rb
you can instantiate records using it
user1=User.create(:email=>"user#test.com",
:first_name=>"user",
:last_name=>"name",
:bio=>"User bio...",
:website=>"http://www.website.com",
:occupation=>"WebDeveloper",
:password=>"changeme",
:password_confirmation=>"changeme",
:avatar => File.open(File.join(Rails.root, '/app/assets/images/profiles/image.png'))
)
user2=User.create(:email=>"user2#test.com",
:first_name=>"user2",
:last_name=>"name2",
:bio=>"User2 bio...",
:website=>"http://www.website.com",
:occupation=>"WebDeveloper",
:password=>"changeme",
:password_confirmation=>"changeme",
:avatar => File.open(File.join(Rails.root, '/app/assets/images/profiles/image.png'))
)
Just run rake db:seed from command line to get it into the db