Rails - best practice to store dictionaries (key value pairs) - ruby-on-rails

I need some architectural advice. I'm more into java, but trying to get up to speed with Ruby-on-rails. In the app I am building I need a convenient place to store some dictionary values that will be later used in various places of the application. These will be usually key value pairs - e.g. list of values to be used in select list.
The main objective is to keep this logic in one place of the application.
I am considering following options:
Store values in the database - i'm kind of reluctant from that, as values won't change very often.
Put all of the values in one class. In JAVA I'd have some static properties in one class holding this values (e.g. call Utils.getStates() will return list of states). How to do it ruby way?
Have some .yml file with values - read from the values. How to do it? I guess I have to parse the file in the initializer, but is there any tutorial how to do it?
Precise example? Let's say that have a model that have a field called "Type". Type can be: ['Type A', 'Type B', 'Type C'...]. And of course, for each type I want to have key and value.
I'd appreciate some suggestions about how you solve this problem in your apps.
Thanks,
Maciek

How often does the list change? Is it acceptable to have developers involved each time a value changes (updating code, re-deploying the app)? If the answer is no then store the values in a database.
Is the list of values reuseable? Then a gem or a yaml file with an initializer might be a good choice.
Is it just a small list and does not change often? Then you might want to consider a constant.

I think in Rails any data that would change at runtime and needs to be persisted, would normally be stored in the database. I think that would be the "rails way". You could save the data to yaml or json file, but that would not follow the normal flow of the MVC pattern that is so common in rails

Related

How can I map/link/associate a UUID to a random hex number

Newbie here, wrapping my head 'round this stuff!
I'd like to use the hex number as my url (external identifier) and keep the uuid within the database for a ruby on rails application. Is this even possible?
Thanks a bunch
Many people advise you against it but, yes, it is possible. It will need some code for it, and the solution depends on which version of Rails you use and what you use for the database, which is why I'm going to answer in a generic way.
You will want to have two different fields for the model: one for the external hex representation and another one for a separate UUID. Then, you can use the hex string to find instances in your controller actions, for example.
Please take a look at the following (they don't seem to have the two fields but will point you to the right direction anyway):
Problems setting a custom primary key in a Rails 4 migration
Change Primary Key Issue Rails 4.0
http://www.speakingcode.com/2013/12/07/gracefully-using-custom-primary-keys-in-rails-4-routes-controllers-models-associations-and-migrations/
And a longer post of a similar thing to do: http://ruby-journal.com/how-to-override-default-primary-key-id-in-rails/
Also, the FriendlyId gem might do what you want.

How to return untranslated keys

For an API, I want to return the actual keyified string.
So:
User.errors.messages[:name]
#=> activerecord.errors.models.user.attrributes.blank
Instead of
Can't be blank
I know I can override this by creating an actual translation, or by setting custom errors in the validates methods in my Models, but I was wondering if there is a lower level, simpler way to make rails return the "keyified" string instead of parsing it through the translation-layers.
I answered some similar questions on SO, but could not find them right now...
I think that this is not possible right now because the ActiveModel::Errors::add method does not store the Key to the message, but just the derived message.
It's also not trivial to reverse get the key from translation files or the like.
I think it would be a valuable addition to rails to actually store the key of the error-message instead of just the message itself.

Ruby on Rails: How to have multiple controllers for one table AND multiple models

I'm new to Ruby and to Rails. I have played a bit with Sinatra but I think that Rails is a more complete framework for my project. However, I am running into trouble with this.
I am working with an fairly substantial existing, and heavily used, mySQL database and I am trying to build an API for this that will report on certain features. The features that are needed are, for the most part, counts of records by certain groupings, then drilling down into details.
For example we have a table - tableA, that contains lots of information relating to documentation. One piece of information we want to report on from that is the number of items in a given language. The language code is stored against each item and based on a get request I would like to return JSON.
Request: /languages/:code/count/:tablename
There are two variables in that most specific URL - the code we are counting and the table we are counting from.
I understand that in routes.rb I can set up a mapping:
get '/languages/:code/count/:table', :controller=>'languages', :action=>'count'
I have a controller - languages_controller.rb with a count method in it. this then matches to a corresponding view file count.html.erb
In all the tutorials I have read and examples I have followed the main point seems that 'languages' would be a table in the database and would therefore be available under the 'magic' Rails approach.
My issue is that it is not a table, rather the results of the call should be a limited subset of the fields in tableA. Such as languagecode and count(id).
The description of the language needs to be looked up 'manually' as it is stored as an internal code that is not in a database anywhere (historic decision/madness).
The questions:
how do I have a model that is only a subset of fields, plus some that are manually populated - languagecode, isocode, description, count
Am I right in thinking that once I have the model defined as such as I could use ActiveRecord to get data from the database and then in the controller add the extra information in?
Can I change table in the model based on the parameter sent in the URL?
Essentially, I am at a loss at the moment on what to do with this. I have the routes defined, the view templates in place and the controller there and ready to go. The database component - getting some data from a pre-existing table seems mysterious to me.
Any help is greatly appreciated, it seems that the framework is currently getting in my way and I know that I can't be the only one trying this sort of thing so if you have any advice please share.
There's really no need for a model here, at all. This isn't what ORMs are for. What you should be doing is just running raw SQL against the database, and iterating over the results. Consider doing something like this: https://stackoverflow.com/a/14840547/229044

How can I most efficiently iterate over a hash of hashes in order based on key value in inner hash?

I've got a JSON hash of hashes returned by a website API that I want to parse and display based on a specific key's value within the internal hashes.
I can think of solutions that would achieve this, but they would take a number of lines of code and don't seem efficient. Surely there must be a way to natively in Rails, given the focus on convention over configuration. I've googled around a bit, but found nothing that covers this issue.
Sample Response from API:
[{"banner":"01197271","birthday":"1991-01-11","committee_id":1,"created_at":"2012-08-08T01:56:02-05:00","email":"me#example.com","first_name":"Dan","graduation_date":"May 2013","hometown":"San Antonio","hours_enrolled":15,"id":2,"image":{"url":null,"thumb":{"url":null},"large":{"url":null}},"invitation_accepted_at":null,"invitation_limit":null,"invitation_sent_at":null,"invitation_token":null,"invited_by_id":null,"invited_by_type":null,"last_name":"Tester","local_apt":"","local_city":"San Antonio","local_state":"Texas","local_street":"One UTSA Circle","local_zip":"78249","major":"Computer Science","permanent_apt":"","permanent_city":"","permanent_state":"","permanent_street":"One UTSA Circle","permanent_zip":"","phone":"5558813284","same_address":true,"tour_trained":false,"updated_at":"2012-08-17T03:35:26-05:00","utsa_id":"uoi431"},
{"banner":"","birthday":"1990-10-25","committee_id":null,"created_at":"2012-08-03T16:19:23-05:00","email":"you#example.com","first_name":"Test","graduation_date":null,"hometown":null,"hours_enrolled":null,"id":1,"image":{"url":null,"thumb":{"url":null},"large":{"url":null}},"invitation_accepted_at":null,"invitation_limit":null,"invitation_sent_at":null,"invitation_token":null,"invited_by_id":null,"invited_by_type":null,"last_name":"User","local_apt":"","local_city":"","local_state":"","local_street":"","local_zip":"","major":null,"permanent_apt":"","permanent_city":"","permanent_state":"","permanent_street":"","permanent_zip":"","phone":"","same_address":false,"tour_trained":false,"updated_at":"2012-08-15T10:05:54-05:00","utsa_id":""}]
Potential solution would be to go through each internal hash, determining value of relevant key value, then store, based on where the key value places it compared to already tested hashes. When complete, return.
Ok so if you have objects that are set up to parse this information, those objects can build themselves based off the parameters of your hash. So you could do something like this
object = MyObject.create(your_hash_parameters)
Where your_hash_parameters are the parameters that you presented in your example.
I'm not sure what would happen if there were more paramaters than your object knew what to do with, if it would still build itself or not. If that is the case, you could use the delete_if method to exclude attributes that are unwanted.
One more note, if this isn't something that you want saved to your database, and its only to display temporary information. I would set up a model with attr_accessors that represent the attributes that you are displaying.
As told in comment, I'd create an ActiveResource object and add relevant methods to it.

Capturing Field Name Metadata from a CSV File in Altova MapForce

I've been asked to prototype a replacement "file transformation process" (that currently is a mess of SQL) using Altova's MapForce. My input is a CSV file with headers. My problem is that I need to capture both the data AND the column name to use in downstream processing.
I need to have MapForce feed a C# method (imported as that takes two parameters: fieldName and value. I can access the value trivially, but after hours pouring over the manual (1000 pages!) I haven't found any examples of how to access the field name as an output.
The reason each output needs the field name and the value has to do with how all our mappings/transformations are currently managed - on a database. The .NET code jumps in at this point and does any necessary database lookups.
For example, if I had the following file:
"Symbol", "Account", "Price", ...
"FOO", "10101", "1.23", ...
"BAR", "10201, "13.56", ...
And a static method string TransformField( string fieldName, string value ),
I'd like to map the CSV file's Symbol data output to the method's value parameter and the Field Name "Symbol" to the method's fieldName parameter.
Some limitations:
I need to keep the "wiring" visible in the MapForce GUI. I'll have non-programmers maintaining the mappings in the future. So doing all this in code is not an option.
MapForce is the tool of choice by the company. Part of the reason our original process is such a mess is because the original programmer rolled his own mapping/transformation tool (out of TSQL no less - ouch).
We can treat all inputs/outputs to the method call as strings. Conversions will happen later.
I would like to avoid using scalar literals as inputs. I already have the column names from the file - I do not want to re-type each one and feed it to my method.
I'm not sure how many users out there have experience with this tool, but after 3 days of tinkering with it, I see much potential. If only I can get past this current sticking point, I think the company will have a solid alternative to their current mess.
Thanks for any/all suggestions.
I solved my issue and, for future reference, want to post a solution. I handled my problem by using MapForce's FlexText. This allowed me to extract the header from the CSV file and "invert" the column names as data inputs to the transformation process. Once I knew the approach to take, I was able to find more information directly from Altova.
I found a couple helpful tutorials while digging through their website:
Altova Online Videos
Web Tutorial
Hope this can help someone else in the future!

Resources