I know Rails' flash hash is nothing new, but I keep running into the same problem with it.
Controllers should be for business logic and db queries, not formatting strings for display to the user. But the flash hash is always set in the controller. This means that I need to hack and work around Rails to use Helpers that I made to format strings for the flash hash.
Is this just a pragmatic compromise to MVC or am I missing something here?
How do you deal with this problem? Or do you not even see it as one?
It appears to be possible to "forcefully" access helpers from controllers. See this discussion here:
http://lojic.com/blog/2007/07/27/using-helpers-inside-controllers-in-ruby-on-rails/
You could also "render" a partial to an instance variable. See this page:
http://snippets.dzone.com/posts/show/396
Normally, if you call "render_partial" within a controller, nothing but the partial will be rendered.
Occasionally, it is useful to render a partial to an instance variable as a string so that the view can still be rendered as
normal, and the string can be passed in to the view.
add_variables_to_assigns
#content_for_navbar = #template.render_partial 'layouts/public_navbar'`
Rails isn't necessarily strictly MVC. In the Rails world, controllers are more like what would otherwise be called View-Controllers in the MVC pattern.
Also, I would argue that in 'pure' MVC, the controllers should not be doing DB queries and business logic—that should be encapsulated in the model layer. Controllers are about moving data between the view and the model.
What about creating helper methods for the view that format whatever you stick into the flash hash? The flash needn't only contain string values; it can contain arbitrary objects. I often find myself putting an array of model validation errors into flash[:error], and writing a helper method to format those messages into a <ul>.
If you'd really like to, you can store a key in the flash variable and then in the view translate that key into an actual message. How the flash displays isn't in any way built-in. It all depends on how much work you are willing to put into it in order to get pure MVC.
The method described by shedd didn’t work for me. The second method described in http://snippets.dzone.com/posts/show/396 did work:
#content_for_navbar = render_to_string :partial => "layouts/public_navbar"
Related
I am building an advanced search feature that would be easily adopted for various entities. This feature would apply to the #index action of desired controllers, hence I've decided to go with a controller concern, hooking a generic partial to each #index of each controller I include AdvancedSearchFeature.
Everything works smooth until I found out that translations are quite an issue. Each advanced search uses different translation keys which should be supplied somewhere, but...I have no clue where it's best to do this.
I've thought:
in the concern, not, because it's meant to be generic;
in the controller where I include the concern, not, because controllers shouldn't deal with translations directly;
in the model linked to the controller, not, because it doesn't feel natural to provide a Model.advanced_search_translation_keys which then should be assigned to a variable to be used in the corresponding view;
in the #index view associated to the controller, not, because a view shouldn't be polluted with translation hashes which should then be passed to the advanced search feature generic partial.
That's why, I've ended up having these translations in...helpers. These helpers are invoked from the advanced search feature generic partial, and if one exists for the desired translation key, it is taken from there. But...I really don't like the idea of creating helpers specifically to return a translation.
Do you have a better idea on how to do this? Maybe you have stumbled upon this issue and solved it somehow else?
Best to nest your translation keys under a namespace, that references your module, and use those keys in a generic view. There won't be any passing needed and your view will be more explicit as to where translations are to be expected to come from.
Assuming you wanted to develop your Controllers so that you use a ViewModel to contain data for the Views you render, should all data be contained within the ViewModel? What conditions would it be ok to bypass the ViewModel?
The reason I ask is I'm in a position where some of the code is using ViewData and some is using the ViewModel. I want to distribute a set of guidelines in the team on when it's right to use the ViewData, and when it's just taking shortcuts. I would like opinions from other developers who have dealt with this so that I know my guidelines aren't just me being biased.
Just to further Fabian's comment; you can explicitly ensure viewdata is never used by following the steps outlined in this article. There's really no excuse not to use models for everything.
If you have no choice but to use ViewData (say on an existing project); at the very least use string constants to resolve the names to avoid using 'magic strings'. Something along the lines of: ViewData[ViewDataKeys.MyKey] = myvalue; Infact, I use this for just about anything that needs to be "string-based" (Session Keys, Cache Keys, VaryByCustom output cache keys, etc).
One approach you may wish to consider as your views become more complex, is to reserve the use of Models for input fields, and use ViewData to support anything else the View needs to render.
There are at least a couple of arguments to support this:
You have a master-page that requires some data to be present (e.g. something like the StackOverflow user information in the header). Applying a site-wide ActionFilter makes it easy to populate this information in ViewData after every action. To put it in model would require that every other Model in the site then inherit from a base Model (this may not seem bad initially, but it can become complicated quickly).
When you are validating a posted form, if there are validation errors you are probably going to want to rebind the model (with the invalid fields) back to the view and display validation messages. This is fine, as data in input fields is posted back and will be bound to the model, but what about any other data your view requires to be re-populated? (e.g. drop-down list values, information messages, etc) These will not be posted back, and it can become messy re-populating these onto the model "around" the posted-back input values. It is often simpler to have a method which populates the ViewData with the..view data.
In my experience I have found this approach works well.
And, in MVC3, the dynamic ViewModels means no more string-indexing!
I personally never use ViewData, everything goes through the Model, except when im testing something and i quickly need to be able to see the value on the view. Strongtyping!
In terms of ASP.NET MVC 2, ViewModel pattern is the preferred approach. The approach takes full advantage of compile time static type checking. This in combination with compiling mvc views will make your development work-flow much faster and more productive since errors are detected during build/compile time as opposed to run time.
with model binding where you can build up an object to ship and bind to the view, is there any reason to ever use ViewData ?
I can't forsee an instance where I would use it unless I had static information coming in from a database for a page/master that then got displayed in say a <p> or some such.
If the page was a read only page that say returned a list of items and I also wanted to display text from a DB then I might use ViewData.
But that's kind of an exception. If I was returning a list of items from a DB along with some other stuff then I would create a Form View Model and simply include any other data in with it.
So rarely I guess is my answer here.
ViewData seems to exist as a simple, convenient approach to something that you really should do a syntactically cleaner way. The MVC equivalent of an ArrayList I suppose- works just fine but you'd be hard pressed to come up with a truly legitimate excuse for using it in good code.
One exception I can think of for using it would be including something dynamic in ALL of your pages that gets appended in an ActionFilter or base Controller class- for example "WebsiteTitle". Rather than attempting to tamper with the data being returned by a Controller action it might make more sense to include something like that in the ViewData collection- perhaps prefixed with some unique identifier to make it obvious it was being included outside the controller action. ViewData["Base_WebSiteName"], for example.
I am pretty new to MVC but what little I have done, I have written custom objects for all my views.
The only reason I could think of is to save time. You need to whip something up fast and maybe there are multiple objects of data on a page and something extra and you don't want to take the time to write an object putting it all together. Is this a good reason? In my opinion no.
I have a Rails site using STI with the following classes:
Pages
Homepage < Pages
LandingPage < Pages
On the front-end all requests get handled by the Pages controller. However, if the object detected is actually an instance of LandingPage, i'd like to have the action on a LandingPages controller get called. (for example, the show method in the child controller classes will pull in some specific lookups that aren't always relevant).
Any suggestions on how to best accomplish this?
Thanks
This sounds a bit like you are clouding the MVC distinction, but it should be doable.
I'd add a series of tests on the Pages model (e.g. supports_buzzbar_foo? or wiggums_itemization_controller, then override them as appropriate in the subclasses) and use these in the view to conditionally generate the appropriate links to the controller methods you want.
That way you're keeping each part (roughly) doing it's job.
Markus' solution should work. You could also keep your links in the views pointed to Pages, evaluate the incoming object and then redirect_to the appropriate controller based on the object class.
However, unless you're performing completely different actions with each type of object, then you'll wind up with duplicate code in your controllers. So you might be better off sticking with the Pages controller and just adding some methods that handle the extra lookups that are needed for that object.
It seems like most people are leaning towards creating single ModelViews for each view (Thunderdome Principle) in lieu of stuffing in weakly typed items into the ViewData dictionary.
So, with this in mind, for what tasks should the ViewDictionary be used for then? Really small one-off views? Don't use it at all?
Never, keep everything strongly typed. Helps with refactoring, that enough is reason alone.
MasterPages strike me as a place where it's tough to get around them. Let's say you have a standard place on all your pages where error messages are going to be displayed. You could theoretically strong type the MasterPage and make sure that all view models inherit from some base class that gives you strong-typed access to the variable for setting the error message in your master page, but that seems like overkill. It's much more reasonable to do something like:
ViewData["ErrorMessage"] = "This is an error message";
and have your master page have a section displaying it:
<div class="error_message"><%= ViewData["ErrorMessage"] %></div>
I think the question is: use strongly-typed Views on not and when?. If your Views are not strongly-typed then you will be using ViewDataDictionary (mostly for simple/small apps). If you are using Unit Testing it is better to have View Model which can be simply tested.