views:

39

answers:

4

Regardless of the language or MVC framework used, how should I handle different views based on roles?

For example (pseudo code):

views/post/show:

<% show post here %>
if (role.isAdmin or role.isModerator) {
   <% show moderation tools %>
}
<% show rest of content %>

I don't quite like the idea of putting too much business logic into the view, but it doesn't seem like there're other options. Are there?

This gets messier and messier once you have more roles, or different levels of permissions. Take this site for example. Users with more than 200 rep see less ads. Users with more than 500 rep have a retag button. Then you get an edit button at 2000, a close button at 3000, moderation tools at 10k, and more functions if you are a "star" moderator.

+1  A: 

There is nothing wrong with this. It's not business logic. It's presentation logic.

Question that this if answers is: should we show moderation tools?
It's not like: 'should regular user be able to delete whole history of payments' or something.

Arnis L.
See my updated question. How would you go about handling multiple or multi-level roles and permissions?
pessimopoppotamus
Then move logic to so called view model. In view You would just check it like `if (ShowAds/CanRetag/CanEdit/CanClose/GotMoreTools){ rendersomefilthyhtml();}`. Or use so called helpers for this.
Arnis L.
How is this not business logic? I thought ACL and workflow was the basic definition of business logic... And that's where we get into the blurred area where the difference between business logic and presentation logic narrows to almost nothing. Presentation logic would be "should I display this element", not "when should I display this element". The when part is business logic (and as such arguably doesn't belong in the view)...
ircmaxell
@ircmaxell You answered question yourself already. model and controller is supposed to provide answers to question 'when'. view just picks it up and shows or hides something.
Arnis L.
+1  A: 

You can make this a little neater by having a custom ViewModel with a boolean property called ShowModerationTools. In your controller you perform the checks to see whether the current user, based on their roles, can see the post and set ShowModerationTools to either true or false. You then return the custom ViewModel to the view. That way you can then just do this in your view:

<% show post here %>
if (Model.ShowModerationTools) {
   <% show moderation tools %>
}
<% show rest of content %>

It also means if your business rules change (for instance you need to introduce another condition) you just change the controller and don't need to alter your view.

Dan Diplo
+1  A: 

I agree with Arnis L. - but will add the following.

You could do this instead...

<% show post here %>
<% Html.RenderAction<MyControllerName>(m => m.ModerationTools()); %>
<% show rest of content %>

This has several benefits.

  1. It encapsulates the Model and View required for moderation tools in a single Action.

  2. It will probably remove the need for you to even have the role on the Model in the page you've posted as an example

  3. It can be re-used on other pages.

Sohnee
Encapsulating might make things more complex. E.g. - view model in this case would hold container property that is actually a view model for partial view. It works well enough if it's only 1 lvl deep, but gets out of control quickly otherwise.
Arnis L.
@Arnis L. Not sure you're right there. The view model would contain no data for the RenderAction statement. That's the whole point of RenderAction over RenderPartial - RenderAction calls an action that has its own separate model.
Sohnee
A: 

Personally, I think what's more important here is the difference between good and good enough...

While technically I think that classifies as business logic, for such a simple case I don't see a problem including it in the view.

Now, if you had more complex logic, I'd suggest creating a new view for each "logic branch", and choosing between them in the controller.

ircmaxell