Versioning domain instances for approval in Grails - grails

I’m looking for the best approach to extend the Grails CRUD generation functionality. It should be a Grails plugin which provides additional generators for following functionality:
Any changes on extended domain instance should be saved (as a version
of it) for history
Only one version of an instance can be active
User should be able to activate a version of the instance (the
currently active instance should be deactivated) which is not created
by him (4 eyes principle)
A diff view is nice to have
The intervention into Grails out of the box scripts should be as small as possible.
I identified so far 3 design strategies for implementation:
Mirror table with the same schema, which contains versions (doubles
the count of domains/tables). The activated version will be copied
to the native domain and vice versa.
Using discriminator in the domain class. Some new columns will be added to the domain (like state [active,notActive], lastUpdatedBy,
lastUpdatedDate…)
(De-)Serializing instances to a special domain with BLOB (e.g domain.properties as JSON)
Any of the solutions has pros and cons. What is the best approach to implement it? Perhaps there is a more simple way.

I've been developing a system in Grails that makes intense use of the version concept (as you related above). My approach was the 2nd one listed in your question.
I've created two fields: internalVersion e disabled. Every class that needs to be Versionable, must implement an interface called Versionable.
I'll try explain here one of the scenarios which it's necessary to use the version functionality (forgive my english).
The system that uses this concept is a Commercial System where there is a class called Quote.
Every Quote can has one or more versions where only the last version is valid. Every Quote and its versions are generated based in negotiations with an specific client. This way, a client asks us a Quote and if for some reason he doesn't like the prices (for instance), we can generate a new version with some discount. Every Quote has a unique code following by the current version, example: QT-000022/0 (first version), QT-000022/1 (second version).
To generate a new Version I use a method that clones the current object (using a kind of complete and deep Save As). I copy everything (properties and collections) to a new object.
The clone method identifies that the class implements the Versionable interface and does the following:
oldQuote.disabled = true
newQuote.internalVersion = oldQuote.internalVersion + 1
This way it's possible assure that only one version will be enabled.
I hope you understand my approach.

Related

Rails how to version the models?

I have created rails application using rails 5 and ruby 2.3. I want to add few changes in some model files and save it as new application. I want two run both applications in production as two similar applications. I know how to version the controller by using namespace but I didn't get solution for version rails models.
Are you saying you want to run two copies of the application in production under different namespaces (e.g., /v1/ and /v2/), both sharing the same database?
There's no easy way, because it's not a good idea. Each time you change to one application, you'll have to remember to change both - and worse if you add more versions in the future.
If possible, you should share one codebase and put any versioning logic in the controller that accesses the model. Your controller can inspect the route that was used to hit it (/v1/ or /v2/) and respond accordingly.
In order to share one database between two versions of your code, you'll need to ensure that any changes you make to the database schema are backwards- and forwards-compatible, meaning you can only add new tables or columns (never rename or remove).
If you don't need the two versions of your app to share the same database, you could give the new version its own copy of the database (database: my_schema_v2 in config/database.yml).
Or you could give the v2 of your model its own table name:
class Product < ApplicationRecord
self.table_name = "products_v2"
end
But again, that means products would not be shared between the old and new versions of your code.

What is the Rails way to handle different controller clients (Web, iOS API)?

I have a Rails app that has 2 "clients" -- an iOS app reads/writes JSON, and Web browsers that read HTML.
Now, if I said "I want different output for different browsers/clients", we could use different ERB files and render based on User-Agent or similar.
In this way Rails was imagined in the Web world -- where I type "cap deploy", and all of my "instances" are upgraded to the latest version (save active session AJAX calls).
As an iOS dev, however, I'm very used to if blocks in code to deal with different data versions & client app versions. It's painful (but required).
I would love to be able to say "I will magically think of the perfect data structure in version 1.0", but we probably all know that's not true -- I'll want to add & deprecate attributes or even models as time goes.
I don't want to mix all of that versioning logic with my normal HTML (which can upgrade gracefully, per above), so I've thought about:
Having a separate controller or just actions for my API calls from iOS
Writing a "forwarder" that treats the HTML/Web version as a layer on top of the API version
Am I trying to solve a Solved Problem? Are there any resources or guiding philosophies I should know about in undertaking this project?
I suggest you create 2 applications, one for the webapp and one for the API.
You could have an external library with all the models, tests and business logic used in those 2 applications.
You can then lock the api to a certain version of the library if needed.
You can create multiple versions of the API without affecting older versions.
You can implement caching at library level if needed and it will automatically affect all applications.
With this model you can also create specific needs, for example, you may want shorter urls for the api than the real webapp, since you don't care about SEO in the API.
What do you think?
Edit :
Here is what I have in mind, library is in the middle.

view a Document at one specific point in time? (dup, versioning?)

Mongoid - 2.4.7
I need to store a copy of a Document at a particular point in time.
I'll know the exact point in time
they'll happen manually (defined like an expiration date)
and will only happen once or twice over life of the document.
What's the best way to do this?
Separate Model(s) - Create separate ExpiredWhatever Models and copy the records when they "expire"? That feels a little gross, especially considering the parent has embedded docs, which also has an embedded docs.
Versioning - The built in Mongoid Versioning could work, but I don't need a version stored on every update, only at 1 or 2 particular points in time. So I'd need to be able to manually set this.
(Also this Parent Document is actually embedded itself; however, that could change as I know Mongoid::Versioning doesn't work with embedded docs.)
So, what's the best way to view a Document (and its embedded docs) at a specific point in time?
You will have to manually do this. I would create another key in the parent document named or prior_version or snapshot_version and store the copy there.
You will need to test to see how mongoid handles that assignment and possibly perform a manual deep copy as you have many embedded fields/docs.
I think separate models is overkill and versioning won't work for this application (as you said, you only need one copy)
From the Mongoid docs on Versioning:
You may skip versioning at any point in time by wrapping the persistence call in a versionless block.
person.versionless do |doc|
doc.update_attributes(name: "Theodore")
end
It's a bit cumbersome, but you can have an if statement that switches from versioned to versionless when you want it to. Ie, save versionless most of the time, but when you set a flag, the if statement switches to the versioned save.

Building consumable uri/urls for a model (rails/datamapper/SOA)

Perhaps you can help me think this through to greater detail.
I need to build or make available a uri for a model instance that can be referenced or used by another application which may or may not be a rails application.
e.g.
I create a standard Post with content; I want to build a URL for that post another application can consume or reference by looking at the model in the database (or another less sticky fashion). Datamapper has a URI field, I want to build a canonical uri, store it there and have another application be able to access, announce, manipulate, etc.
Basically, I have several applications that may be in different places, that need to access the same model, to do differing things with the model. I need a way to make that happen clearly without putting them all in one monster application.
I've looked at Pubsubhub, RSS, etc. but haven't found any concrete examples of what I'm trying to do. Do I need to create an common API for the applications, etc?
DataMapper is very flexible about using existing databases.
Many people come to DataMapper because it can create and tear down the database structures without migrations. However, you do not have to work with it in that way.
I have had good success with using a large set of models owned by a central 'housekeeping' app and then declaring a small subset of the same models in separate 'interface' apps.
Some trial and error is required to figure out what works but it can certainly be done. I'd suggest putting your models in modules and including them across apps if possible.
A final point it sounds like you want URIs/URLs to be the primary interface. If that is the case I strongly suggest you look at Sinatra. It is entirely oriented around URLs (and I find Rails routes very obtuse).

Generate new models and schema at runtime

Let's say your app enables users to create their own tables in the database to hold their own, custom data. Each table would have it's own schema. What are some good approaches?
My first stab involved dynamically creating migration files and model files bu I'd like to run this on heroku where you can't write to the filesystem.
I'm thinking eval may be the way to go to create and run the migration class and the model class. But I want to make sure the model class exists when a new process of the app is spawned. Can probably do this by storing these class definition with each user as they create new tables and then run through them all at startup. But now it's convulted enough that I may be missing something obvious.
It's probably a better idea not to generate new classes on runtime. Besides all of the security risks, each thread's startup time will be abominable if you ever get a significant number of users.
I would suggest rethinking your app design and aim at generic tables to hold the user's custom data. If you have examples of data structures that users can create we might be able to help.
Have you thought about a non-sql database for those tables? Look at CouchDB - there are several plugins on Github that integrate it with rails. Records in the database are JSON documents, with arbitrary key-value structure. May be perfect for a user-defined schema.
There is (was?) a cool Wiki project, called Informl. It was a Wiki, not just for web pages but for web applications. (Get it? It's informal because it's a Wiki, it's got forms because it is an application, and it's user-generated, thus Web 2.0, which means that according to an official UN resolution it is legally required to have a name which is missing a vwl.)
So, in other words, it was not just about user-generated content, but also user-generated structured data.
They did this by generating PostgreSQL-specific SQL at runtime to create new tables and then have ActiveRecord reload the schemas.
The code is up on RubyForge. It's based on Rails 1.2.3. I guess you could do much better than that today, especially with the upcoming extensibility interfaces in Rails 3.

Resources