Restless Rails

Is Rails moving to a pure RESTful design? I don't like REST but love Rails. I'd hate to think that as Rails develops it will become more difficult to use it RESTlessly.

After moving to Rails 2 a few months ago I've been looking to create new elements of my applications using the newer RESTful techniques and the more I try, the more I dislike the way it works.

The final screw in the coffin for me was when I scaffolded a new controller (I was in a hurry and needed to get something working quickly). I noticed that each action had a comment above it showing the URL path-component that would take the user to each action. That summed up for me what I don't like about the new REST based system - I don't want the choice of action to be something I have to think about.

With the old style 'controller\action\id' URL it was simple for me to work out which action in the controller I was using. With the newly favoured system I have to keep asking myself "is this a get or a post". The fact that the writers of the scaffold code felt they had to add reminders above each action, suggests to me that others find that it is not intuitive as to which action is being used at each point.

I think the new URLs go against one of my goals of writing self commenting code whenever possible (one of the reasons I like Ruby so much as it makes that easy).

At the moment it is easy stop the RESTful stuff. Just don't add the 'map.resources :controller_name' statement into routes.rb (or remove that statement if scaffolding puts it in for you). However, I can see a point when it's asked "why do we have to keep adding these statements to routers.rb? Why don't we just assume a controller will be RESTful?". Then suddenly the choice of whether to be RESTful or not could disappear.

I think it is fine that other developers want to create RESTful application and can do so easily with Rails. If it works for them ....

However, I'd hate for Rails to develop to the point where the decision is no longer available to the developer as to whether or not to be RESTful.

As a RESTless Luddite I hope that Rails doesn't become REST only.

Sorry, I can't see your problem. Are you talking about REST or CRUD anyway?

The CRUD actions only cover basic functionality and that for there will always be an alternative. If you need other actions, just define them like:

map.resources :payments, :collection => [:search, :export_paypal],                                :member => [:accept, :pdf]

This is far better readable than the old way and you get the URL helpers like: pdf_payment_path(@id)

And controllers won't be "all CRUD" by default, since even a REST resources often doesn't use all CRUD actions and there is not much sense in adding "empty" actions to the controllers. So if they would decide to have those actions in by default, this would still be only an option, nobody can force you to actually write code in such an action.

Thorsten Mueller wrote:

Are you talking about REST or CRUD anyway?

REST. You can use CRUD without using REST.

CRUD describes the separate handling of Create, Read, Update and Delete. You can have separate new/create, show, edit/update, delete/destroy actions in either a RESTful or RESTless controller.

REST defines how you get to those actions and it is that I dislike.

Rob Nichols wrote:

Is Rails moving to a pure RESTful design? I don't like REST but love Rails. I'd hate to think that as Rails develops it will become more difficult to use it RESTlessly. ...

Rob, I couldn't agree more with you. I don't see any advantages on using restful resources unless one is developing web services or something like.

I myself have written another non-restful scaffold generator in my own native language for starting up my CRUD controllers. I based myself on the restful scaffold generator and changed the views, controller and tests to reflect the good old days Rails used to be.

The non-restful is much simpler than the restful approach with less code written and much easier to understand, unless one is willing to deliver web services...

Here is my suggestion: write your own non-restful generator. This is very simple. Maybe someone maintains a plugin for adding this non-restful generator. If not, it would be pretty easy to do.

I'll not write it since I already have one for my own language (brazilian portuguese) and I'm concentrating efforts for contributing to Rails documentation when I have time and to think in another multi-language views support when I have time. If it works, I'll write another internationalized plugin with a different approach than Globalize and GetText, but with lots of the GetText idea, since I used it a lot for Desktop development and were satisfied with it. But it is not well designed for views translation. It was designed for short messages translation, which is common in Desktop development.

Best regards,

Rodrigo.

Rodrigo Rosenfeld Rosas wrote:

Rob Nichols wrote:

Is Rails moving to a pure RESTful design? I don't like REST but love Rails. I'd hate to think that as Rails develops it will become more difficult to use it RESTlessly.

This is just my 2 cents: You have chosen an opinionated framework, you likely knew that when you started using Rails. The point to REST in Rails has little to do with web services, it's about applying convention to the structure of controllers and request routing. REST makes adding a web service API on top of your application easy, but the point is still the convention and not specifically to make web services.

As for me I'm a big proponent of the RESTful design. In other words I happen to agree with the opinion of Rails. That does not mean that you should agree with the opinion yourself.

So will Rails continue down the path to RESTful patterns? I'd say the answer to that is very clear. Can you still design your applications today without using the RESTful convention? Sure you can. Will it be more painful? Probably.

I would say in your situation: maybe it's time to evaluate whether Rails is "in-line" with your opinion because your individual opinion is not likely to affect the opinions of the core team (who have obviously embraced a RESTful design).

"If you've boarded a ship headed toward a destination that you don't want to go, then maybe it's time to start looking for a port where you can board another ship."

Guys:

I spent about a year fighting RESTful design in Rails for the reasons you’ve outlined. I don’t like things that are “cool” most of the time. I like things that work.

However, the more things I’ve done with RESTful design, the more I truly appreciate it. The thing is that people can explain it to you until they’re blue in the face but you’re never going to “get” it unless you have experienced it successfully.

For me, it was forcing myself to think about making everything work within the default seven actions (index, show, create, new, edit, update, destroy). You’d be surprised how often that works.

Need to view something? GET to show and pass the id. Need to view all things? GET to index Need to create something? POST to index Need to change something? PUT to update and pass the id Need to remove something? DELETE to destroy and pass the ide

Really, there’s nothing different here than what you’ve done all along.

<%=form_tag {:controller => “posts”, :action=>“create”}, :method => “post” %>

still works just fine.

However, the REST convention makes it a lot easier.

<% form_for @post do |f| %>

If @post is a new record (no id, or id is nil, then the helper knows it needs to POST to the create action. Just like how activerecord doesn’t need to be told what the primary key is, or what the table name is.

If @post has an id, then it knows the form needs to be a PUT request to the UPDATE action.

Similarly, while I can do this: <%=link_to “Create a new post”, :controller=>“posts”, :action=>“new” %>

I can just do

<%=link_to “Create a new post”, new_post_url %>

In controllers and tests, it works together too!

if @post.save

go to the list page

redirect_to posts_path else …

def test_should_redirect_to_list_when_created_successfully Post.any_instance.stubs(:save).returns(true) post :create assert_redirected_to posts_path end

So, what I’m saying is that once you learn how it all falls together, you actually have less to think about.

"Where does the “change password” stuff go? new action called “change_password”? No! It’s an update! Maybe an additional view to show the form for requesting the change, but the change itself is an update.

"Where do I do a search for posts? a “results” action? No! The index action alreadt returns all the posts paginated by 20 at a time, just pass your querystring there and use the controller to narrow the results down.

I’m more than willing to help any of you wrap your heads around this because it’s been a long journey for me to get here and I wish I had someone to help me get where I am. I’d love to save you the trouble.

I don’t, however, think that the “old style” ways are going away.

Brian,

Thank you for your very nice over-view of using REST.

However, I think it also demonstrates one of the problems with the Rails' REST system. It simplifies things when you have a straight-forward requirement, but complicates them if you need to do something outside that model.

For example, how do you handle a situation where you need to allow a user to modify multiple instances of an object within a single list view? Do you really want your user to go through a complete 'list, edit, update, list' sequence twenty times to change one field on each of twenty items? Far better I believe to present a single list of the twenty items and let them submit the changes to all twenty in one form submission.

It is an update of the whole list. You just need to create a controller for the list, and not for the items.

I think in that situation I'd have an 'update_multiple' controller action, and declare a custom route, it can still be RESTful because you'd use a PUT to update the group of items. It gets fiddly to work with if you have something more complex than the basics. I do agree that REST isn't always the solution and simply isn't the solution in some cases.

RobL

Rob Nichols wrote:

Yup.

This is exactly why you can do

map.resources :apartments, :collection => {:update_all => :put}

Like every convention, there are problems, and there are solutions to that problem. Think about ActiveRecord. There are a few edge cases where the conventions just break down. But just because you can’t do everything with AciveRecord doesn’t mean you throw it out and do everything with DBI and execute. :slight_smile:

Hi All,

I would advise you to look at recipe 13 "Handle Multiple Models in One Form" from Advanced Rails Recipies (by Mike Clark, sold by pragmatic programmers). It a little too big to post here, so buy the PDF. I'm using it and it works great.

Questions like these have been around for much longer and clean solutions to this have been invented by smart people. Read their stuff, it helps. Don't try to invent the wheel yourself.

Regards, Bas

Yes, I'd do it with a custom controller method too.

Bas van Westing wrote:

Hi All,

I would advise you to look at recipe 13 "Handle Multiple Models in One Form" from Advanced Rails Recipies (by Mike Clark, sold by pragmatic programmers). It a little too big to post here, so buy the PDF. I'm using it and it works great.

However, it does assume the list of items belong_to another class. Of course I could create a class to hold those items, but I think it would just be easier to create a custom controller method.

Don't try to invent the wheel yourself.

Surely that cliché is inappropriate as it is the wheel that is reinvented itself. I'm the Luddite that's resisting the reinvention. If anything I could be using that cliché myself asking the Rest advocates to stop reinventing the wheel :o)

However, my point isn't that Rest is bad, but rather that it should not be the only way to use Rails. I hoping that Restless Luddites like me will not be excluded in the splendidness that is Rails.

"Where does the "change password" stuff go? new action called "change_password"? No! It's an update! Maybe an additional view to show the form for requesting the change, but the change itself is an update.

But then wouldn't you need an extra action (GET change_password) to display that additional view with the form requesting the change? The form on that view would issue a regular PUT to UPDATE the entire record, sure, but somehow you need to be able to invoke that form...

Also, what if you want to display a message saying 'We've changed your password' instead of the regular 'We've updated your entire record'? Then you'd need an extra parameter on the PUT account/id action, to indicate that you've called this action from the 'change_password' form. Wouldn't you? Or am I missing something?

Thanks for your help.

Rob Nichols wrote:

Is Rails moving to a pure RESTful design? I don't like REST but love Rails. I'd hate to think that as Rails develops it will become more difficult to use it RESTlessly.

As a RESTless Luddite I hope that Rails doesn't become REST only.

Rob, count me in RESTless club. Rails is a beautiful thing but it is not perfect. DHH is a brilliant guy, and probably is smart enough that he "just doesn't get why some people don't get it". Be that as it may, I'm willing to take what I do know and understand about Rails and continue to use it for fun and profit.

I don't feel the need to "force myself" to do it the way the cool kids do. The "old way" of doing Rails works much better than anything else I've tried, and happily, so far at least, they haven't done anything to reduce the ease with which us Luddites can use it that way.

For me, REST is a lot like Calculus. I had to learn it (sort of) to get my degree. I know it can do powerful things in the right hands, and yet somehow I've managed to get promotion after promotion, decade after decade...never having used it once as an Engineer.

Rob, let the cool kids and the "I'm smart enough to get it" crowd continue to belittle us for not using REST. Let's just get the show on the road and keep cranking out cool apps by the dozen that work well despite being RESTless. I'm still getting better at Rails with each successive app, despite not forcing myself to "do it the right way". I can be successful without being "right".

cheers, jp

Exactly, but you can be a little smarter about it.

When you do update_attributes, it's gonna take whatever you pass it. A lot of sites put the "change your password" field on the same page as the other profile stuff but they make it a separate form submit, so the password fields are the only fields sent up.

A different Flash message could be built if you wanted to. Is it necessary? usually not cos they know what they entered. "I saved your stuff" might be enough. If it isn't, you already have the information you need to make a different Flash notice happen - the name of the submit button. By default, it's "commit". Give it a name. If the user clicked it, it will have a value :slight_smile: If they didn't it won't exist (nil).

If you wanted the "change your pw" to be its own page, then yes, you'd use an additional GET method that's not RESTful to do that. However, that's ok. These "present the interface" methods are just fine. That's why you have EDIT and NEW. Where you start becoming unRESTful is when you start doing things like def export_to_csv and def search and def results. (can all be handled by the index action)

Does that help?

-Brian

Does that help?

Makes sense. Thanks Brian.