How to properly version Ruby on Rails APIs? - ruby-on-rails

When talking about Ruby on Rails API versioning, it's common to create a division in the controller level. They create new routes with new controllers in different modules, such as API::V2::ProductsController and so on.
The problem is: not all the code is in the controllers. Even a simple Ruby on Rails application has its code shared between models, views (which in this case would be the serializers) and controllers. Not to mention jobs, mailers and application specific libraries (lib/ directory) code.
Even if you version the controller with new controllers with different routes, the model would be the same for every version, and so would be the views and the database schema itself.
I know ActiveModelSerializer, one of the most used serializing gems, does implement versioning, but still, Rails models don't support versioning by default.
Is there a way to really version a Ruby on Rails API?

I would say that your view layer: your serializers or .rabl or .jbuilder files should contain as much presentation logic as possible (ideally all!). Thus: how this data is displayed to the user: a pretty formatted string, a JSON document with a certain structure, a JSON document with a slightly different structure.
If you have a User model, and you want to format the date a user joined the site, don't implement a User#dateUserJoinedISOStr method, but instead in the serializer get the date field and do the transformation to the proper iso string there.
Then you can switch on the API version requested, or use a completely different serializer if the changes between the two API versions are just too different.
Theoretically maybe you even think of the two api versions as different representations of the same resource, and use / abuse Rails content type format tools to pick the right content template.
This of course gets harder if you have a site that returns HTML as well as JSON (or, to put it a better way, "HTML representations in addition to JSON representations"). In that case I'd either use some clever route magic such that the version comes through the params OR buck convention a little bit and don't put a version number in your URL path (instead use a header!). Regardless, if your routes always go to the same place, then either have some if statements in the controller (to select the correct version serializer) OR a bunch of if statements in the serializer ("display that now, or not?").

Related

Inspect RoR json API

Is any way (I mean RoR code) to enumerate
exising API endpoints
input data with data types
output data with data types
something else
Let suppose we use ruby on rails and our api is based on models and its types.
( Something like with schema here )
What is possible and how?
What is not possible and why?
This is generally not possible.
The controllers (and models) in a Rails app define on various layers what data to accept. This is generally not defined in a static format but through a layered validation process (e.g. on the controller with strong_parameters and the models with their validations.
Since those validations can define arbitrarily complex business rules using Ruby code, usually, you can thus only check if a given data structure is accepted by trying to pass it to the app and checking if it accepts it without any errors.
With that being said, there are gems which allow you to define "abstract" API schemas which might be consumed by external clients and used to validate data in your app. Examples here are trailblazer, dry-validation, json-schema and others. Note that these approaches usually require to follow the architectural requirements of these gems which might heavily affect the way you design your application.

Should I prevent making I18n translation calls in models

This is a question merely about code style.
I am working on a multilingual app in Ruby on Rails 4. My personal feeling tells me ideally to not do calls to I18n.t() in models, I just think model methods should be consistent, and not depending on varying environmental situations like the current user's locale, especially since I18n is usually related to views. I've got a few questions about this though:
Do you think this is a good rule in general?
How should I manage error messages in custom validation methods? Should I make exceptions for that scenario?
How should I manage customised keys that we use in form fields, such as the displayed text of a collection_select, that are partially translated? Is there a way to use view helpers for these occasions, that is (almost) as convenient as building model methods for these?
Yes. Translations belong to the view layer and only to the "display" part of it (that is, not to the API, which is still view)
Error messsages should be standard enough so you get to translate them correctly by iterating them in the view and getting the piecewise translations. Unfortunately that's not always possible because of different grammatical order of the sentences in languages. Still it's not useful to move those translations to the model. ActiveRecord's Errors class has hooks for translations just like ActiveModel, so the view can rely on them without injecting any i18n in the model itself.
Select helpers can often take a lambda as a label generator, you can use and abuse view paths and relative i18n keys and whatever you need without having to inject anything in the model. In case of doubt, use a presenter and inject I18n in it.

Collection of text files in place of rails database

I'm currently constructing a Rails site to edit a collection of files used for configuration of various services. The files are simple plain text files. The point of the site is to provide an easy interface for editing the files as well as validate changes for the less technically incline individuals who will be editing them.
I've looked around but I can't seem to find anything on using text files instead of a database. What I do find suggests that what I'm trying to do may not be correct for rails at all. The closest thing have is this question, but the answers are less than helpful.
Is there a correct way to create an MVC for text files and not use a database at all?
Yes. Rails provides MVC with activerecord being default for models. you can keep rails views and controllers (VC part) and write your own models (M part). Imagine using mongoid ORM instead of active record. For that reason rails provides activemodel to make it easy for people to write their own models that are backed by different storage mechanism. look at https://github.com/rails/rails/tree/master/activemodel to get started on writing your own ORM that will use text files as backend instead of SQL database. Also include http://api.rubyonrails.org/classes/ActiveModel/Lint/Tests.html in your model test files to verify that your models conform activemodel api. After that, you can use rails form helpers in views and routes with your models without problem.

Rails app with non-HTTP access

Hypothetical question (at the moment!)
Suppose I have a great idea for an application. It acts on data which can be well-represented by tables in a relational database, using interlinked objects which represent those tables. It supports a well-defined API for interacting with (Creating, Reading, Updating, Deleting) those objects, and viewing information about them.
In short, it's a perfect fit for Rails... except it doesn't want to be a web-app. Perhaps it wants a Command Line interface; or an OS-native dialog-based interface; or perhaps it wants to present itself as a resource to other apps. Whatever - it just isn't designed to present itself over HTTP.
These questions suggest it's certainly possible, but both approach the problem from the point of view of adapting an existing web-app to have an additional, non-web, interface.
I'm interested in knowing what the best way to create such an app would be. Would you be best to rails new non_web_app, in order to get the skeleton built "for free", then write some "normal" Ruby code that requires config/environment - but then you have a lot of web-centric cruft that you don't need? Or would it be better to roll up your sleeves and build it from whole cloth, taking just the libraries you need and manually writing any required configuration?
If the latter, what exactly is needed to make a Rails app, but without the web bits?
If you want to access the Rails ORM to develop a CRUD non-web application, just include ActiveRecord in your own Ruby script; you will avoid using a lot of Rails modules you probably don't need (routing, template generator, ...) Here is an example of how to do it.
If you prefer to have the full Rails stack, do not run your Rails web app in an application server (WEBrick, Passenger, Mongrel, ...) to avoid any HTTP exposure, and interact with your application using tasks or the rails console.
I would avoid taking Rails too far off the rails. If I were doing this and felt that the gains of rails w/o the web stuff I'd do the following:
rails new non_web_app
and ignore the webbish cruft and use rails to generate models. In this way you get the tight, comfortable database behavior and can tie various gems in as you want to augment those models. I'd not bother implementing views, of course, and I'd consider implementing controllers in which the various render bits are removed and to use you instantiate an instance of the controller and call the action directly. This means the controller represents your API into your business logic still but the "views" it now "renders" are simply the return of the data output.
Then you could simply strip out the bits you do not need...the public directory, the view structure under app, config/routes.rb, etc. You'll need to test those changes incrementally and make sure that removing some now extraneous bit doesn't throw the Rails world into chaos.
Rails is for Web apps. That means HTTP. Now, you could package a Web app so that it runs on the desktop instead, or you could use ActiveRecord with a desktop application framework like Monkeybars.

Helpers in rails

I'm just starting out in Rails and there's a lot I still need to learn so I'm likely to be on Stackoverflow more often than normal asking beginner Rails / Ruby questions.
I'm just trying to figure out how Helpers work in Rails. From what I've seen so far, Helpers are intended to be used with Views and not so much with your Controllers.
However I would like to make a simple function that will validate the user input given in params (check if certain params are defined and optionally check if their value is valid).
Can anyone explain to me what would be the best way of implementing this? (Keeping in mind that I will want to use this in many different controllers so it should be globally available.)
I also noticed that by default Rails does not generate a lib folder in the main application folder. Are developers to place their libs outside the app folder in the main folder, or does Rails use libraries differently?
With regards to your validation issue, it depends on what you are validating.
If the data makes up objects from your problem domain, also known as models, then you should use the built in validators from ActiveModel. This is probably what you should do, but its hard to say without knowing the exact problem. See the Rails Guides on Validations. You can tell if this is the case by asking yourself if the data that needs validation will be stored after you get it. If so, its most definitely a model. An example of this kind of data would be the title and text fields of a blog post being sent to Rails from a browser form.
If the data is something tertiary to your models, or specific to presentation, then you should be fine using helpers. You noticed that helpers are used mostly in the views, and although this is true, theres nothing stopping you from using them in the controllers, you just have to declare that you will use them using the ActiveController#helper method. Inside the ApplicationController class, a lot of devs will put helper :all to just include all the helpers in all the controllers. Once the code has been required once, it doesn't really incur that big a performance hit.
Do note that almost all incoming data can be modeled using a model. A big school of thought in the Rails world subscribes to the Fat Model idea. People say that putting as much code as possible in the model and as little in the controller as possible separates concerns properly and leads to more maintainable code. This suggests that even if you don't think the incoming data is modelable (in the sense that you can create a model to represent it), you should try to make it a model and encapsulate the logic around validating it. However, you may find that making a helper function is faster, and either will work.
Your notion of validating user input is a good one. I get the feeling that as you are new to Rails you are used to doing these things yourself, but that doesn't quite apply here. In the Rails world, a lot of the common stuff like validations is handled by the framework. You don't have to check for presence in the params array, instead you call validates_presence_of on the model and let Rails spit the error out to the user. It makes things easier in the long run if you let the framework do what it is designed to.
With regards to your question about the lib folder, it doesn't really matter. You can put miscellaneous support files and libraries in the lib folder in the root directory and they will be available for use in your application (the files in the app folder). You can also choose to abstract your code into a plugin or a gem and include it that way, which a lot of people opt to do. My suggestion for this would be to read up on the notion of gems and plugins before diving in.
Want you want is probably a custom validator (in Rails3):
http://railscasts.com/episodes/211-validations-in-rails-3
You can either add libs in a lib folder you create, or add them to config/initializers in a file you add. Files in the initializers directory are automatically loaded by Rails.

Resources