Rails: How do I keep a complex app RESTful? - ruby-on-rails

I always try to make my applications as RESTful as possible but I've recently begun working on a complex project that requires multiple additional methods in my controller.
I normally achieve this by adding another :collection to the route but it seems like a workaround and in on scenario I have 5.
Are there any best practices for handling the extra methods in a controller? They are generally simple forms that updates a model.

The other solution, which is what I do, is every time you find yourself creating an action that doesn't fit into the RESTful actions, eg Search, so you might find yourself making a search action on an Article controller, what you could do instead of creating this action is create a Search controller instead, and use RESTful actions inside of that instead. There is no rule saying you need to use all the actions, you might only need one or two, but it keeps your API RESTful and your code organised.
This is not a hard and fast rule, but I have certainly found it helpful when I try to decide where to put stuff.

I think there's a bit of confusion in the Rails community about how and where to use the word "RESTful". Strictly speaking, the only thing that can be RESTful is your web API (as railsninja already mentioned). That the code of an application that conforms to the REST conventions (the application with REST API) can usually be organized into a set of controllers (that match the resources) and methods in these controllers (that match the four verbs of the HTTP protocol) is nothing but a hint of how to keep your application clean and organized.
If we want to talk about a RESTful Rails application, we can't just talk about RESTful controllers - there's nothing RESTful about just controllers themselves. It's possible to have a complex web application with only one controller (and myriad of methods) that represents many resources and is perfectly RESTful.
That said, it's pretty OK to add more methods to your controller. Sometimes, it's good to extract some of these extra methods and create a completely new controller - make this any time you feel good about it (rule of a thumb: create new controller anytime you are able to identify it with some self-sufficient resource, ie. a resource which could exist just by itself). Sometimes though, it'd be silly to extract some resource to a different controller. Say you have a resource which has a status attribute. It makes sense to perceive this status attribute as a resource by itself and perform at least one action on it (update), but it won't make any good to extract it to a different controller.

There is a Railscast about this topic, adding custom actions to an otherwise RESTful controller.
Edit: I see that you've mentioned the method in the Railscast as a workaround already. :-) I believe the only other "pure" way to handle it would be to add additional controllers as required to support the actions you want.

"I normally achieve this by adding another :collection to the route but it seems like a workaround and in on scenario I have 5. "
This sounds perfectly fine to me. REST is not about the crud operations and your concern seems to stem from the fact that you are doing more than the basic crud operations but there's nothing wrong with that.

Related

Does this approach to fat model/skinny controller take it too far?

I am afraid that I might be getting lazy.
I am developing a ruby on rails application involving about 8 models relating to two types of users: physicians and patients. Most of the logic is inside the models allowing my controller actions to be very short and concise. Plus, it makes the testing fairly straightforward.
I currently envision at least two controllers and the tests that I am writing lead me to believe that most of my user-facing features can be handled by these two controllers. Sure, I can break this into more sensible compartments-like tests for a patients-controller, physicians-controller, patient-medications controller, patient-lab-results-controller and so on. But it seems to me that the only advantage here is more discreet organization.
On to the question, asides from compartmentalization, what are the reasons NOT to use as few controllers as possible, pack them with lots of actions [disadvantage], but keep the actions skinny [advantage]? Or...to take it to an extreme: Why not with MVC, have a bunch of fat models, and one skinny [albeit long] controller rather than a patient controller/model/views+tests for EACH, physician controller/model/views+tests for EACH, etc?
There's organization, as making everything inside a single controller is possible, it's going to be harder to understand and change. Instead of being able to open a file in your editor and finding the action you're looking for right away, you would be scrolling down the file to find what you're looking for.
This also leads to the God object pattern where everything happens inside a single object that's responsible for everything and everyone working at the project will be changing this same object, leading to an eternal merge hell.
And, on Rails itself, there's the RESTful-ness of the framework. Rails embraces the idea of being RESTful and one of the pillars of this idea are the resources and they can only be easily organized in separate controllers. If you try to place two different resources at the same controller you'll probably end up with crazy routes or crazy controller logic to find out which model is being represented.
If you think your controllers have a lot of repeated code, you can DRY them out using some metaprogramming magic or conventions, but it's really better to have them separated, not only for organization but also to simplify your own future maintenance.
If there's a lot of common controller logic, you might consider abstracting it out into a plugin or module that you can mix in when needed. Or the controllers could inherit from a common base controller (much as all controllers inherit by default from ApplicationController, rather than ActionController::Base).
I would advise against having one gigantic controller; a controller should manage the set of actions which pertain to a single type of resource (or the closest analog possible). This idea is even stronger if you are trying to create a RESTful design, in which each controller typically has nothing other than the basic seven actions (index, show, new, create, edit, update, destroy).
So if you want to have URLs like /patients/52394802/lab_results, I think it makes complete sense to have a LabResultsController. If these controllers are lightweight, awesome. I'm of the opinion that their existence is still justified. This shouldn't stop you from trying to make your code DRY; rather, I would simply try to abstract away the common functionality differently.
That's an impossible question to answer. Controllers are about routes and user interactions and views not business logic. Have as many controllers and actions that it makes sense to have for your links and views!
If your business logic is all in your models then it's simple enough. The main difficulty with logic in controllers is that you can't re-use the logic.
Nothing much more to say really. It's up to you to do what makes sense in your app. e.g. have a search controller to search for stuff rather than adding a search action to your existing controllers is not really about anything more than separation and clarity

Keeping a controller thin (too many action methods)

I'm working on my first real ASP.NET MVC project and I've noticed that the controller I've been working in is getting rather large. This seemingly goes against the best practice of keeping your controllers thin.
I've done a good job keeping the business logic out of the controllers. I use a separate layer for that. Each action primarily calls a method in the business layer and coordinates the end result based on whether or not the modelstate is valid.
That said, the controller has a large number of action methods. Intuitively, I would like to break the controller down into sub-controllers but I don't see an easy way to do that. I could simply break the controller down into separate controllers but the I loose the hierarchy and it feels a bit dirty.
Is it necessary to refactor a controller with a large number of thin actions? If so, what is the best way to do this?
First, when you hear that it's good to keep controller code to a minimum, this mainly refers to keeping each action method as thin as possible (put logic instead into business classes, not into Views and ViewModels.) It seems you're doing this, which is great.
As for having "too many" action methods, this is a judgment call. It could actually be a sign of good organization, that you're having each action focus on one thing. Also, maybe you're using actions specifically for use with RenderAction? And, it could just be the nature of your solution that there are many things to do relating to your Controller's theme.
So, my guess is that you're probably fine. However, to make sure, on note paper break out the controller into 2 or 3 controllers, and sketch out how your stories would work moving from action to action. And if you find that your workflow works with more controllers, you should break it out. Especially if you're going to be adding to this functionality later. The sooner your break it out the better.
Good question.
I believe a "thin" controller may still need to be "wide" or "tall" depending on how you want to stretch the analogy. If there is no clean way to break up a controller that needs to do a lot of things, I don't think that's a problem as long as each Action is focused exclusively on preparing Views/ViewModels and is of limited code size.
Another structural option you have is introducing partial classes for logical groupings of actions. And using something like vscommands to group the files together.
I doubt anybody can come up with a magic number of actions that tells you when it's a good idea to break stuff up and introduce new controllers, it really depends on your domain.
Another solution can be to separate the controllers based on the business concepts of the actions that are included in them, but the route of each action is in accordance with the REST rules.
However, I think it is better to use this solution only in cases where there is a fat controller, otherwise, it is better to categorize actions based on their output resources.

How to use the same model with Rails for different controllers while staying RESTful

I need to have two separate pages on the site I'm planning to build that are very similar that I don't need to introduce new DB tables or models. I would also like to stay RESTful.
If I'm to use the same controller/model I will need to have new methods other than standard index, new, edit...etc which makes it non-restful or I will have to have a variable on page that identifies it and then inside each method I will render different view accordingly.
Another idea I got was to have separate controller and model but use the same DB tables and enforce the model to use the table although it doesn't match the convention.
I'm guessing there might be cleaner way to do this. Do you know any? if not which way do you suggest?
Thanks,
Tam
I'm not afraid of the restafarian police! Sometimes your controllers need more than the 7 actions (where's the get to confirm a delete, eh?), sometimes they will need less. That's just the way it is when you start to create real world software.
If the actions you're adding are not coherent with the actions that exist (for example off by just a little bit but still off in most actions), then we're talking about a new controller IMO - otherwise adding a few actions where you need to is ok in my book.

Architectural best practices - where to put non-REST actions?

I'm making my first real Rails app, and am learning about REST architecture and how it fits into Rails apps. My controllers don't really seem to map logically to an individual resource, so it's tough for me to implement strict REST. For instance, I have a "catalog", "checkout" and "admin" controller, not a "products", "categories", "orders" and "users" controller, although those are the main resources being used in those controllers. Each of the controllers does more than just REST actions on a resource however, all of them pull from multiple models and service multiple views.
Am I missing a design/architectural practice that would make REST work better here? Namespaced controllers perhaps, with non-REST actions in the top-level controller only, and REST actions in the sub-controllers? Seems like I would run into some DRY violations there...
If this is the way you want to structure your app, forget about REST and just map the routes you need. If you don't actually want to manage resources why bother?
REST is great for resources. It's really painful to map a checkout procedure as a restful resource and not worth the effort, personally, I just have 4/5 actions in my checkout controller and that seems to do the job.
If you want the helpers, you can map named routes
checkout_delivery_path
map.checkout_delivery '/checkout/delivery', :controller => "checkout", :action => "delivery"
If you look at the HTTP spec here
you will see that one thing that POST can be used for is:
Providing a block of data, such as the result of submitting a
form, to a data-handling process;
So, you can create a controller that is a "data-handling process" and do a POST to it without violating any REST constraints. If you name the resource with a noun you can make URL feel a bit more RESTful, but it really is not not necessary. e.g.
POST /MyStore/CheckoutGirl
As for your Catalog, I don't see why that doesn't map easily.
GET /MyStore/Catalog/Item/2324
GET /MyStore/Catalog/SaleItems
The admin usually maps to users, roles, etc. There is nothing new there.
Stop trying to shoehorn every aspect of REST into every application. REST is an architecture, and it's not suitable for all purposes. If what you need is some RPC action, then use some other form of RPC, not the resource-centric principles of REST.
Also, the URL naming schemes are totally irrelevant to whether your application is RESTful or not. That's not what REST is about. They're nice to have, but just do what makes sense for your application.

Should rails ajax calls be bundled into their own separate controller?

Should AJAX calls that are not RESTful be:
put in the controller that most suits their functionality/view, or
bundled together into their own separate 'Ajax' controller?
I've been doing 1, but I've just read this (2725 diggs) article
http://zygote.egg-co.com/10-dirty-little-web-development-tricks/ (see point 9)
and this chap opts for method 2. But he is a PHP developer though.
One benefit could be that 2 might clean up the routes by doing something like 'ajax/:action' instead of adding members to restful routes.
It seems like a 6.5 of one, half a baker's dozen of the other type thing.
Which option do you go for?
I prefer the first approach:
it's semantically consistent. if an Ajax action involves resource XXX, you (and other coders) will know where to find things in your application, thanks to Rails conventions.
if your application is heavy on Ajax (and nowadays most of them are), you will end up with a behemoth AjaxController that negates the whole RESTful thing. The rest of your controllers will be there just to provide gracefully degraded non-javascript CRUD actions.
Similarly, testing your Ajax controller will tend to be somewhat messy because you will have to set up scenarios --load fixtures, mocks, etc. for each and every "ajaxified" resource of your app.
Your "RESTful" controllers probably include new and edit actions, neither of which are actually RESTful, they just provide user interfaces for the create and update REST actions. new and edit don't get a separate NonRestUIController or something, they are kept in their associated resource's controller, keeping your controllers semantically consistent. Similarly, Ajax actions that relate to a certain set of functionality or a certain resource should stay in the associated controller.

Resources