(Rails) Adding new model with initial data to existing app - ruby-on-rails

I've an existing web app that is running in production with user data and various other types of data. I want to add a new model with some initial data for the same.
The data should be there when it goes live. This new data is a one time thing and I don't ever want it to be put back into the database in the future.
I couldn't find an answer to this specific scenario that I have. What is the best way to do this?
Thanks!

Related

Best design pattern to handle iOS Application State/Data

I am starting a new project (learning purposes) and I am trying to figure out what is the best software design pattern to use in the following scenario.
I have several data that need to be downloaded from multiple webservices and store somewhere in my app, to display it later. However each piece of data (e.g. list of teachers, students) will only be used in one or more specific view controllers (e.g. teachersViewController and studentsViewController).
I read that the Singleton pattern or use the AppDelegate to store a variable (an object like ApplicationData) is a bad practise, even more in this example which I want to restrict the data access.
So, which design pattern should I choose? I have read something about dependency injection, but I don't have any clue about it or if it even helps me in this question. If it helps, some examples with explanation would be nice.
You need some sort of database to store downloaded data. Good choices are Realm and Core Data. The right way to process data is:
Check if data is already in DB and show it if available.
Download or update data from server and parse it to objects.
Save objects to DB.
Show data taken from DB to user.
Download data as needed. When you open VC with students then download only students data and so on.
EDITED: If you need all the data on app open then load it and put in a DB before first screen opens. Then just use DB to show data to user.

Ensembles and Core Data Light Migration

I am currently doing some tests with Ensembles, specifically testing Core Data light migration.
My current configuration is as follow:
Device-A running my app with data model 1
Device-B running my app with data model 2
data model 2 is based on data model 1 with one additional string property, which is optional
My scenario is as follow:
At the beginning, running my app with data model 1 on both Device-A, and Device-B, everything synced fine using Ensembles (iCloud configuration)
On Device-B, install and run my updated app using data model 2
On Device-A, keep running my old app using data model 1, and add a new record
The result: the new record added on Device-A is uploaded to iCloud and then synced to device-B
My question: can I configure Ensembles to prevent it from uploading changes to iCloud in case that related data model is not the latest one? (i.e. in my case, Device-A uploads an object based on data model 1 while iCloud is already based on data model 2)
Thanks in advance!
UPDATE 1:
Drew, thank you very much for your answer. I definitely agree that uploads can't (and probably shouldn't) be prevented as Ensembles is a decentralised, peer-to-peer system.
In the ideal case, I would like that the device with the new data model will ignore data that is based on the old data model. (in a similar way to the existing behavior where the device with the old data model will ignore any data based on the new data model). Is that supported?
If not, please consider the following scenario as an example:
The old data model has an entity called 'Book' with two properties: title, and author (both fields are non optional)
The new data model has a new optional property called titleFirstLetter that should hold the first letter of the title field.
Currently, when Ensembles is not involved, I have full control when saving new NSManagedObject to the persistence store. Therefore, the updated code of my app which responsible for adding a new book, will make sure to extract the first letter from the title field and save it to the new titleFirstLetter property. (i.e. a book titled Catch-22 will have C in the titleFirstLetter property when book is saved).
In addition, when light migration occurs on the core data stack, I detect that, and perform a one-time procedure where I iterate all existing books in the database, and set the titleFirstLetter according to the title value. From this point and on, the database is consistent and valid, while the new code will ensure that future books added to the database will keep database valid.
Regarding Ensembles, if I don't have any control on old data coming from devices with older data model, how can I fill the new property of titleFirstLetter, if my code is never being called?
Thank you for your kind assistance!
You can't prevent it, no. Ensembles is a decentralised, peer-to-peer system. There is really no way for one device to know the current state of another device, so you couldn't prevent an upload.
The updated device should be capable of handling the old data from the other device. The device with the old model will ignore any data based on the new model, until it too is updated. Then it will merge all of that ignored data.
It is best to avoid migrations where possible, and stick to simple stuff like adding properties or entities, rather than tricky refactors. If you need to make a lot of changes, consider simply starting with a new ensemble (e.g. change the ensembles identifier).

Rails: working on temporary instance between requests and then commit changes to database

I have already read Rails - How do I temporarily store a rails model instance? and similar questions but I cannot find a successful answer.
Imagine I have the model Customer, which may contain a huge amount of information attached (simple attributes, data in other tables through has_many relation, etc...). I want the application's user to access all data in a single page with a single Save button on it. As the user makes changes in the data (i.e. he changes simple attributes, adds or deletes has_many items,...) I want the application to update the model, but without committing changes to the database. Only when the user clicks on Save, the model must be committed.
For achieving this I need the model to be kept by Rails between HTTP requests. Furthermore, two different users may be changing the model's data at the same time, so these temporary instances should be bound to the Rails session.
Is there any way to achieve this? Is it actually a good idea? And, if not, how can one design a web application in which changes in a model cannot be retained in the browser but in the server until the user wants to commit them?
EDIT
Based on user smallbutton.com's proposal, I wonder if serializing the model instance to a temporary file (whose path would be stored in the session hash), and then reloading it each time a new request arrives, would do the trick. Would it work in all cases? Is there any piece of information that would be lost during serialization/deserialization?
As HTTP requests are stateless you need some kind of storeage between requests. The session is the easiest way to store data between requests. As for you the session will not be enough because you need it to be accessed by multiple users.
I see two ways to achive your goal:
1) Get some fast external data storage like a key-value server (redis, or anything you prefer http://nosql-database.org/) where you put your objects via serializing/deserializing (eg. JSON).
This may be fast depending on your design choices and data model but this is the harder approach.
2) Just store your Objects in the DB as you would regularly do and get them versioned: (https://github.com/airblade/paper_trail). Then you can just store a timestamp when people hit the save-button and you can always go back to this state. This would be the easier approach i guess but may be a bit slower depending on the size of your data model changes ( but I think it'll do )
EDIT: If you need real-time collaboration between users you should probably have a look at something like Firebase
EDIT2: Anwer to your second question, whether you can put the data into a file:
Sure you can do that. But you would need some kind of locking to prevent data loss if more than one person is editing. You will need that aswell if you go for 1) but tools like redis already include locks to achive your goal (eg. redis-semaphore). Depending on your data you may need to build some logic for merging different changes of different users.
3) Another aproach that came to my mind would be doing all editing with Javascript and save it in one db-transaction. This would go well with synchronization tools like firebase (or your own synchronization via Rails streaming API)

How do I perform Core Data Migration to an existing app, if all I'm changing is the SQL Db's content?

I've checked a lot of sites and answers and I can't find any solutions specific to my problem.
I don't need to change the schema for my Core data model, all I need is to modify (add some) content to the current backing SQL Database.
Any direction on this will be welcome. Thanks.
PS: I tried Apple docs and they were about as useful to me as sunshine on Mecury.
Also go easy please, I'm a beginner.
Thanks.
UPDATE;
To shed more light on my issue, my app works as thus. I have preloaded static information on the app that can't be changed by the user, each day has new content. Every month, I push an update with entirely new content specific to that month. However, when my app entered production, upon the update I pushed for this month, my users were complaining that they couldn't access the month's data. This led to me spamming them with Push notifications to have them delete the app and do a fresh install to access the new data.
How can I fix this issue? my schema stays the same, only the data changes.
If I understand correctly you want to pre-fill a Core Data database ?
If you don't care about pre-existing data on existing app, you can make an iPhone or Mac app with the same model, and let it generate the database, like explain here (Any way to pre populate core data?) it's also the way recommended in a really great book if you want to learn more about Core Data (http://pragprog.com/book/mzcd2/core-data).
Do not ever make SQL request directly, Core Data work in his own magic way.
Don't work on the SQLite-Database directly. Change all your Data through NSManagedObjectContext! To find a good strategy look up examples from Batch-Importing.
Update: You could actually have two PersistentStores (one with just static data (readonly) and the other one with user-generated data). You could interchange the readonly which you prefilled with a commandline util and downloaded from a server. You cannot have direct relationships between those two store though.
I would say that it depends on the amount of data in this prefilled store wether you should go this way or just use a plist and reference some string constants in your user data store. Try to do it with a plist as this is the simpler approach.

How to split an iOS sqlite db?

I have an existing iOS app that uses core data for app data and user data. My problem is that updating app data is a nightmare (my first app, so I didn't do it ideally the first time). I would like to split the app data and user data into 2 separate sqlite dbs (or stores, correct me if my terminology is wrong).
Any tips would be appreciated.
Having two sqlite files is a good idea. The pain is splitting them now.
Create a new store that only exists in your app bundle. Make sure the data is unchanged from when you first released the app.
You are going to need to walk the "user" store and find all of the data that is identical to what exists in the "reference" store and delete it. If the user has changed that data then I would leave it and let the user sort out duplicates.
Once that is complete your app can resume normal function and load up both stores. I would set a flag somewhere so that you know this has been done and you don't run the check on every launch. The "user" store's metadata is a good place.
Note, this will need to be done before the user can "use" your app. This probably means changing your launch routines so that if a migration and filter is needed you tell the user what is going on.
I don't think having multiple persistent stores is the right solution. You can simply have separate entities within a single persistent store. Core Data will handle it properly.

Resources