At the moment I'm implementing versioning for our REST API in our Rails application. Is there a way this can be implemented so you only define new functionality in new versions? Say for example:
I have a Users controller and a Products controller. Products has stayed the same between V1 and V2, but Users has changed. It would be nice if we could set it up so that if I call for V2 of Products, my application knows it doesn't exist and simply uses the most recent controller version instead (in this case, V1). This would allow for us to not create a whole new set of controllers for every version; we'd only create new controllers for the specific functionality that has changed.
Below is a snippet from our Routes.rb, and admittedly I have no idea how to tackle this problem. Any help would be greatly appreciated!
namespace :api do
scope module: :v1, constraints: ApiConstraints.new(version: 1) do
resources :users
resources :products
end
scope module: :v2, constraints: ApiConstraints.new(version: 2) do
resources :users
end
end
I've used the same strategy for sometime and recently changed approaches-and admittedly I'm biased because I'm also one of the authors of our new approach with VersionCake.
This approach is to only version our payloads or views, afterall views are the contract between the client and if there is a breaking contract change, then the version needs to change. In VersionCake, you can version your views like so:
app/views/products/show.v1.rabl
app/views/products/show.v2.rabl
app/views/users/show.v1.rabl
The specific feature that is important based on your question is that VersionCake will gracefully degrade to the latest supported version. Given the example above, a client requesting users/1.json for version 2 will receive the payload for users/show.v1.rabl.
All this being said, it would require adopting a new versioning approach, so it might not be the best answer, but I think it's an option worth considering.
Have you looked at Grape already?
What I have done over the API's I have built is, when something changes for all of them (like authentication) I just get them all to inherit from a specific versioned api controller, as in Api::V1::BaseController and place the common behavior and controls in there.
Since changing the API usually also meant changing the representations, using a tool that generates the representations for your is also really important, there are many gems out there for this as:
RABL
Roar
Jbuilder
This is what Grape is designed to do.
In addition, you have the option of mounting your API in your routes.rb file or mapping it in config.ru, bypassing the Rails stack and greatly improving the performance of the API.
Related
I am writing my first "real" Rails app after making a few successful learning projects and I'm still a little bit iffy on best practises for App vs API routes. Ideally, API routes will be RESTful, mainly revolving around using resources :articles or whatever, but I'm wondering which of the the following two scenarios is best
Create the app itself using RESTful routes, then bolt on an API in the "api" namespace/subdomain for example, and after authentication, piggy back off the same routes (not sure exactly how to do the piggy backing yet with different authentication, but that will come later. Or;
Create the app itself with whatever routes are semantic and work well (still ideally CRUD based), then create an entirely new set of controllers and routes for the API (RESTful)
I appreciate any feedback that anyone has.
The default "Rails way" is to make your models available to different clients through a single set of URIs, handled by a single set of controllers — /articles for browsers, /articles.json or /articles.xml for programmatic access. You can see that in Rails' emphasis on "resources", the respond_to mechanism in your controllers and so on.
This often works very well for simpler APIs that match the CRUD semantics closely. If yours for whatever reason does not, you might be better off with separating it out.
Try starting out the simple way by sticking to this 'one controller for both' approach. If you like, you could use
scope '(api)' do
resources :articles
resources :authors
resources :comments
# ...
end
to add an optional '/api/' path segment to your URLs - in this case, giving you both /api/articles and /articles, routed to the same controller. This gives you an easy way out, should you later decide to switch to separate controllers for HTML and API access.
I have to cook up a super-simple Rails app with the following functionality:
Only one model: Update. Updates are simply news that my client will be publishing on the site, i.e. basically mini blog posts. An update has three fields: headline, text (both mandatory) and image.
The client will need to log in to create, update, & delete updates. No roles and authorization levels are necessary — just a single login / password combination for the above tasks.
It's desirable to have a very basic WYSIWYG (for inserting links, etc) in the UI for creating & editing updates.
It's been a while I've done something similar, so the question is: is it advisable just to roll everything from scratch or are there gems I should consider?
(I'll be probably using AWS and CarrierWave for images).
Much thanks!
Simplest way to achieve this (and yes, it will be relatively simple) will be to use the Devise gem with InheritedResources. Here's how:
Flow
Firstly, you'll want to ensure you're able to give the use a place to compose & submit the updates. To do this, you'll want to create a simple backend (admin) system, to give you a separate space to update your backend:
#config/routes.rb
namespace :admin do
resources :updates, path: "", except: :show #-> domain.com/admin/
end
root: "updates#index"
resources :updates, path: "", only: [:show, :index] #-> domain.com/:id
The importance of this type of system is relevant.
The issue I think you're alluding to is the way in which you won't be able to either create or access the various mini-updates from a "protected" area. Using the method I'm detailing will only only provide this area, but also give you the ability to store the data correctly.
--
Controller
To get this to work, you'll need two controllers:
#app/controllers/updates_controller.rb #-> for general users
class UpdatesController < InheritedResources::Base
#InheritedResources will create relevant CRUD resources
end
#app/controllers/admin/updates_controller.rb #-> for admin
class Admin::UpdatesController < InheritedResources::Base
before_action :authenticate_user! #-> for Devise
#InheritedResources creates relevant responses
end
The above two controllers are really the core of what you need. They provide the CRUD functionality for both the admin and `general areas of your app - giving you the ability to provide the users with the ability to upload as they require.
The biggest thing you need to consider is the authentication. This is handled with Devise (which I'll explain below). The thing you need to consider is the authenticate_user! call - this is what determines whether the user is able to invoke the methods, depending on whether they are logged in (maintain an active session) or not
--
Devise (authentication)
The Devise gem will be what you need to get the authentication of your app sorted. This is what you're asking about -- and simply, it's a job for Devise.
There is a great tutorial on how to handle this here:
The bottom line with Devise is that you need 3 things to get it working:
A User model
A users table
The Devise columns & system installed
Without over-burdening you, I'd just recommend using the controllers I put up above (with the corresponding views), the routes, and then Devise
It's not a gem, but you could look at Rails Composer: https://github.com/RailsApps/rails-composer - they have templates for generating apps that meet your needs. It lets you set options to help you customise them further.
I have a decent amount of experience with rails, but I've always been a bit ad hoc with my development methods. I'm curious about how to be properly RESTful in rails. Here's an example of an app I'm working on now:
I have a few models, including a User, Pack, and Product model. The models each have a controller associated with them. If I want to create a new page called 'Dashboard', on which the User can create new records on the Pack model, as well as see their account information, how do I do this in a restful way? Do I create a new controller called Dashboard? Or do I add it to a controller that defines my 'Static Pages'? What's the best practice regarding pages that aren't exclusive to the actions on one model?
Thank you in advance!
Yes, basically you want one controller per resource. In this case the resource is a combination of things but since you've identified a singular meta-resource (a "dashboard") it makes sense. So, I'd create a DashboardsController and then have a route like:
resource :dashboard, only: :show
Then you can use dashboard_url for links to the dashboard.
NOTES: The singular resource in the routes file is important because it indicates you don't have a list of resources, just a single one. This means there won't be an index action and the show action will be the default -- thus dashboard_url doesn't require a resource to show to be passed to it. And, regardless, controllers are named in the plural -- thus DashboardsController.
I would create a DashboardsController despite not having Dashboard model. Then to maintain REST principles have a controller method :new and controller method :create. Simply disply the information on the dashboards/new.html.erb but have the form post to the :create controller action.
To supplement the answers already given, REST really exists to make an easily-consumable API. (Notably, Roy Fielding's work is in the area of APIs, and REST is built on top of HTTP methods that HTML doesn't allow.)
This has been a common stumbling block since RESTful routing debuted in Rails; people get the impression that every controller now needs to be RESTful and that the front end and API should never diverge. Frequently, though, the front end and API have different needs.
For resources you want to be accessible via an API—Products, Users, Packs—trying to be RESTful is ideal. For those sorts of uses, pdobb's advice to have one controller per resource is generally exactly what you're looking for. They make sense in the context of an API being consumed by a machine.
But what about the dashboard? Dashboards are generally an HTML view intended to be rendered in a browser and viewed by a human being.
Does a "dashboard" resource make sense in the context of an API? Would it make more sense to instead make that data available in other resources? Is that data available in other resources?
Even if a "meta-resource" aggregating data still makes sense, would it be more logical if the API version had another name, like AccountSummary?
The default route file has the following segment:
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
So what exactly is the problem with letting Rails assume the controller, action, and view to display when the format is ':controller(/:action(/:id))(.:format)' ? I mean, for more specific things like nesting I can always use specific routes...
It's just a common-sense security measure.
It forces the designer to whitelist GET requests so that the app does not inadvertently divulge the contents of a table or record to a malicious user.
If developers are allowed to being lazy, they will be. We are super great at optimizing efforts.
Not being explicit about routes may help you save 5 seconds each time you have a new controller, but it will be a headache for new developers, which will be unfamiliar with your codebase and hence don't know how things are glued. They will have to reverse engineer your views-controllers.
Being there. Not pretty.
Being explicit is usually better.
Because not everyone is building the next Facebook and some of us do this for fun or to make simple apps that we use only on our development device or to simply not be a ass and "answer" a question with that actually has an answer, instead of make ourselves look uber smart and important:
match '/:controller(/:action(/:id))(.:format)', to: "#{:controller}#{:action}", via: [:get, :post]
In the process of making an ebook, users have to edit its content, edit its metadata, choose marketing options, (such as pricing and distribution) and publish.
I started to put each everything inside the Book resource (contents, metadata, marketing options etc)
Then each step of the process (contents, metadata, marketing) is an action inside BooksController.
But Books started to grow a lot in terms of attributes and actions.
I'm wondering if it is better to force RESTfulness by creating singleton resources, each associated to their respective book.
The routes would be:
/book/12/content/edit
/book/12/metadata/edit
/book/12/marketing/edit
This seems more elegant, as each of these "resources" are RESTful and have few attributes each. But the resources are not objects (Marketings?).
Do you thing it's OK to create meaningless resources just to be RESTful and keep code in order?
Is there a better way to group similar attributes than create resources out of them? Thanks.
I'm porting a large PHP application to Rails and we have a fair few "ad-hoc"resources, such as admins have the ability to log in as another user with their permission, in order to correct issues etc. I would always complain that features such as logging in as other users should not be bundled into a huge monolithic AdminController as actions loginAsUser and logOutOfUserAccount. In our Rails app we try to visualize as much as we can in terms of resources, so using the example I just gave, we have an Admin namespace, under which there is a UsersController (/admin/users/:id) and as a sub-resource of users, we have a UserOverride resource (/admin/users/:user_id/override)... it feels really logical that we just POST and DELETE to this resource.
So getting back to your example, yes, I think you should break those sections down into separate resources. It certainly seems like BookContent should be a sub-resource of Book, and MarketingOptions too.
resources :books do
resource :content
resources :marketing_options
end
etc
This is both nicer to work with (more modular) and easier to visualize just from looking at the routes alone. You also get the benefit of really predictable path helpers:
<%= link_to("Marketing Options", book_marketing_options_path(#book)) %>
You can't try to force every conceivable route into a RESTful resource ideology though... if it feels like it's forced, then it probably is.
There's a decent blog post I wanted to link to that (despite some poor grammar) actually does a pretty good job of showing you how to think about your application in terms of resources... I can't find it though. I'll add a comment if/when I do.
EDIT | Just re-reading your original question and wanted to clarify: resource != row in database. A resource is anything you can conceive as a "thing"... I know that's a very broad statement, but just like an Object in OOP doesn't have to represent something concrete/material, nor does a resource in a RESTful design.