resources_controller part II
February 14th, 2007
Update: check out resource s controller update
Update: point 3 below (broken in rails < edge) is now solved. (non-edge) Rails <= 1.2.2 users should also install this plugin.
(this is a followup to this entry)
There were some problems with resources_controller as released a couple of weeks ago, including:
- No support for name_prefix, which crippled the url_helpers
- Limited support for polymorphic resources
- Broken in rails < Edge, due to the fact that scoped creates for associations are new.
- Lack of test support to show me the above
The 1st, 2nd and 4th points have been thoroughly addressed in the latest release, and if you run the tests you'll find out if your version of rails is susceptible to the 3rd point. The solution to the 3rd point should be pretty trivial and will appear soon.
(Thanks to Igor Alexeiuk for pointing me in the right direction on the above, and for contributing some code for name_prefix stuff)
Here's an example of what you can do:
class TagsController < ApplicationController resources_controller_for :tags nested_in :taggable, :polymorphic => true, :load_enclosing => true end
The above controller can be used to service all of your models that have tags, wherever they're located in the resource schema. The controller will load the enclosing resources (raising RecordNotFound if the relationships don't match) and the named routes will also work.
Take a look at the test app to see what the new syntax is like, and what the plugin is capable of here
February 20th, 2007 at 10:05 PM
Thanks so much of this plugin, it's another piece in the puzzle helping me understand rails and rest. And now I've got a question. Lets say I have these to classes, the Forums model has a to_many to posts, and posts has a belongs_to to forum. In the controllers I've done this:
The problem is that it doesn't seem like the forum_id column of the post is getting set when a new post is created. Before switching to resource_controller I had something like this in my create method for post
...So my question is what's the best way to ensure that new posts are added to there enclosing forum using your plugin. Thanks for any suggestions.
February 21st, 2007 at 04:14 PM
Hi Jesse,
You’re probably not on edge rails - if this is true, then you need to also add the plugin mention at the very top of this post (in the section marked ‘update’)
The reason is that calls to new on associations are scoped in edge rails (at least that seems to be the reason). This means that a ‘new’ will automagically passed the association foreign_key. In rails less than edge you need to set this yourself (as in your example) or use ‘build’, which is what the plugin does.
Let me know if it works for you,
Cheers,
Ian
February 22nd, 2007 at 12:15 PM
Hi Ian,
Included is a small patch to your plugin resource controller that:
Fixes a small mistake in the flash message when the destroy action runs.
Removes the explicit usage of new and find in ResourceService and replaces them with the more generic method_missing method.
The reason for the first change is obvious, but the reason for the second change isn’t.
I have pagination methods that take an association object and use it to paginate through the records. I’d like to be able to just hand in the ResourceService object and have it work just like any other association object, which is why I use method_missing instead of just explicitly defining each of the methods it uses.
Also I have one suggestion. In the module that defines all the base actions for the controler, it explicitly does one of the following at the top of each action:
When I override any of the supplied action methods, I have to remember to add those same lines of code to my actions. It would be DRYer if they were set up in before_filters, and in the rare case where I’d want to do something else, I could just use skipbeforefilter to turn off those filters, or override them by creating my own filters.
So if there were 3 filters defined:
And before_filters could set up like:
This seems to cover the normal usage case that your plugin seeks to handle, while cutting out a bit of code in the overridden actions.
What do you think?
–
Thanks,
Dan
February 23rd, 2007 at 08:53 AM
Hi Dan
Thanks for the patch, and suggestions.
I’ve applied your method_missing patch slightly differently. For performance reasons I’ve not replaced find and new, but simply added method_missing. This should do the trick for what you have in mind.
I’ll think about the other stuff and get back to you (work time has finished for me today). What you propose seems like a good idea. I’ve been having similar thought wrt declaratively specifying the responds_to part of actions. The idea being that if you want to add, say, an atom feed to index, you’d do something like this:
instead of rewriting your entire index method.
Your idea and this idea seem to be of the same vein (splitting actions into smaller, overridable, units). And it also potentially applies to more than just resources_controller.
Because of this, I think that it might be better in it’s own plugin.
On a side note, you can achieve what you wanted right now with resources_controller by writing your own Actions module like so
and then
Finally, would you mind if I posted this conversation as comments on the blog, I think it might be interesting for others.
Cheers, Ian
February 23rd, 2007 at 08:53 AM
Yup, I knew about this. I’d been using this since I don’t like the way the standard scaffolding works for create, update and destroy. Specifically I don’t like the idea of having to rely in cookies/sessions and then redirecting the user to another action to see the flash messages. Cookies used to store state that modifies the response is considered a REST anti-pattern. I try hard to avoid it when I can.
If the same end-goal can be reached without cookies or redirects then I say why not.
So, in my application.rb I do:
And then I use :actions_include to pull in the following module in my controllers:
I have a simple rescue_action method in application.rb that catches any of the normal AR exceptions like:
.. and displays the correct status code (1409, 422 and 422 respectively.
Yeah, for sure.
Thanks,
Dan
February 26th, 2007 at 05:33 PM
Ian,
Thanks for your help. You were correct, I wasn’t on edge rails, and moving to edge rails solved the problem. Now I’ve got another quick question.
Using my initial setup with Forums, Posts, Comments… Now that I’m on edge rails and using resources controller when I create a new comment it is assigned the correct postid. GOOD! But in my setup comments also have a userid, and I’d like to set that to the current user when a new comment is created.
My original setup before moving to resources controller looked like this:
Now that I’m using resources controller I’m trying to duplicate that same behavior like this:
But when I do that it seems to run a validation on the comment forum before the initial display. That means that when a user first creates a comment they will initially see lots of errors about missing attributes even though they haven’t yet had a chance to fill anything in yet. I’m sure this is a pretty basic rails thing, but so far I haven’t been able to figure it out. Could you point me in the right direction? Thanks.
February 27th, 2007 at 10:20 AM
Hi Jesse,
Glad you got the first problem sorted out. (Feel free to email me on ian dot w dot white at_ gmail _dot com by the way).
As for your next problem, concat’ing the comment to @current_user.comments will try and save the comment, thus causing the validation errors you mention. Since the comment is under construction, perhaps you want to do this:
def new_resource returning resource_service.new(params[resource_name]) do |comment| comment.user = @current_user end endBe sure that your Comment model contain the following:
Make sense? Does that work for you?
Cheers, Ian
February 27th, 2007 at 08:22 PM
Ian,
Thanks yet again. That change did the trick.
But I’m confused. Why is it that adding the comment to the current user’s comments collection forces a save, while assigning the comment’s user to the current user does not? Is this a ruby rails thing, or something to do with your plugin? If it’s a rails think where can I read more about the “hows” and “whys” of it?
February 27th, 2007 at 09:12 PM
It’s a rails thing.
But, like most rails things, it makes a lot of sense.
When creating a comment, you’re specifying one of its attributes - that it has a certain user (comment.user = @current_user).
When you’re adding a comment to the user’s comments, it needs to be the case that the comment exists (otherwise what comment are you adding?) That’s why rails tries to save the comment if it’s a new record. (In fact rails can delay the save, but only when the user you’re adding the comments to isn’t yet saved).
Make sense?