Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to organize actions that don't fit into the normal MVC

I am creating a survey application so I created a surveys controller that behaves very restfully creating, updating, etc a Survey. However now I'm adding other actions to it like 'take', for taking a survey, and 'share', for sharing a survey. There are more actions too. I'm starting to wonder if I should organize my code differently and move those new actions into their own controllers however I'm not so sure take or share or some of my other actions really fit into REST really well. They almost make more sense as actions if I wasn't a little worried about the survey controller size.

Either I could leave it the way it is or I was thinking of creating a survey namespace and creating like Survey::TakeController and the Survey::ShareController. Then I would then I guess use the new action or index?

I'm not exactly sure the proper way to do it. If I do create a survey namespace should I then move the orginal SurveyController in it? That would make some weird looking methods like survey_survey_path.

like image 361
hadees Avatar asked Jul 30 '10 06:07

hadees


1 Answers

To think RESTfully, you should probably stop thinking of them as "controllers with actions" and start thinking of them as "objects that can be created/updated etc" - controllers are just proxies for the views that show the results of creating/updating an object.

A lot of the time, I've found that an extra action is really just a variation of "update" - just with its own special requirements (eg only certain people can update it or whatever). That sort of logic can often go inside the model itself (eg "MyModel#can_be_edited_by?(some_user)").

Sometimes you find that actually you have an extra "hidden" model that needs its own RESTful interface.

Eg with your "take" a survey - I'm guessing, but what you have is something like a "SurveyResult" and a person can "create "survey" but when they "take" a survey, they are actually creating a "SurveyResult" (the other commentor called this a "SurveyParticipation" - but it's the same thing).

The thing being that you will probably have multiple SurveyResults that each belong_to :survey and belong_to :some_user_model.

Then you can set up nice restful routes such as: /surveys/123-my_favourite_colour/results

which will return a set of all the results for a single survey

This is actually the RESTful way to view this part of your object-space.

As to sharing a survey - that's a more intersting question. It depends on how you've got your authorisation setup for "sharing". It also depends on what you mean by "share". Are you sharing the results of a survey, or sharing the survey-object itself (so another user can edit the questions) or are you (as a person that has just taken part in a survey) sharing a link to the survey so that your friends can also take the survey?

For the first two above - I'd consider a "SurveyPermission" class that belongs_to :survey and belongs_to :some_user_model. The you can create a SurveyPermission for another user - and Surveys can be edited by the creator- or anybody that has a permission to edit it. Thus the share action is to create a SurveyPermission. Though to be honest - your SurveyPermission is likely only to be used for create and delete, so it may be simpler to stick those two actions in the Survey controller.

For the latter - well, that's just sending a "create_survey_result(@survey)" link to somebody...

Update:

I don't generally bother with namespaces unless there are two resources named the same thing (but in different contexts). You only need namespaces to disambiguate between them and that doesn't seem to be the case here.

In this case - the only namespacing that occurs is in the routing:

map.resources :surveys do |s|
  s.resources :results
  s.resources :shares # ???
end

gives such routes as:

new_survey_path
surveys_path
new_survey_result_path(@survey)
survey_results_path(@survey)
like image 194
Taryn East Avatar answered Nov 15 '22 04:11

Taryn East