I am experimenting with implementing BEM helpers in my Rails 4 app to help me write views more pleasantly.
Let's assume we have the following Haml view:
= block :user_bar, unregistered: current_user.unregistered? do |b|
- if current_user.unregistered?
= b.element :inner do
You are not registered.
Assuming the block and the fictional class BEMBlockBuilder with a method #element (of which an instance is passed as b) are defined, and assuming that current_user.unregistered? is true, we should get the following HTML output:
<div class="user-bar user-bar--unregistered">
<div class="user-bar__inner">
You are not registered.
</div>
</div>
This technique should make it possible to set up blocks, elements and apply modifiers to them without having to repeat the block's name every time, and it would make it possible able to apply modifiers simply based on the value bound to them being truthy.
The technique itself is somewhat similar to what happens when you use the form_for helper, in that it passes an instance of FormBuilder to the block.
The primary difference between this technique and the form_for helper is that you may end up using a multitude of nested blocks to render a view, of which the output might not be known.
Would this technique affect Rails's (or HAML's) ability to perform caching in a negative way, or would it damage rendering performance in general?
No, the implementation you are suggesting does not negatively impact caching - This includes page caching, action caching as well as Russian doll caching.
While the cases for page caching or action caching are fairly obvious, the reason Russian doll caching is also unaffected by custom view builders is because if the cache_key of model does not change - the block passed to the cache helper does not get re-evaluated irrespective of the view builder that is getting invoked underneath.
The above assumes that you avoid implicit state in your builder. Alex has already highlighted the importance of predictability in the comments.
Apart from that the only key issue is that streaming of templates will be tricky to handle. If that is not relevant to your use case, then you are good to go. In particular, if you are using HAML then you can not use streaming anyways. You may however consider exploring the thread for some interesting ideas on handling streaming templates.
If you want to avoid this issue, you may consider using small helper functions just to generate the class names according to BEM. Then you can use something like:
<div class="<%= bem_class(block: 'user-bar', el: 'inner', mods: ['unregistered']) %>">
</div>
This is obviously more verbose, but also easily allows you to handle cases where multiple blocks are applied to same DOM element, which is valid in BEM.
Finally, here are some key takeaways from an extremely well written article by Justin Weiss on view rendering performance assessment:
Sacrificing maintainability for marginal gains in performance is rarely a good solution
Complex logic does not belong in the views
Profiling tools are your friend.
Related
In a fairly large rails application we are running into the issue of overly complex views. Most of the views have too much logic.
Views have between 2 and 4 related instance variables, and make use of various logic checks and helper methods to render the view.
Here is a fake example:
<% if authorized?(#user) %>
<!--some html-->
<% recent_projects(#projects).each do |project| %>
<!-- html & helper methods -->
<% end %>
<!--some more html-->
<% else %>
<!--some html & helper methods-->
<% end %>
Presenters, Facades, and helpers:
I've been researching using the facade and/or presenter pattern to help expose the functionality we need in the view while extracting and isolating the complexity.
My Question is:
Where does the html live? Do I make several small view partials and render them conditionally from helper methods? Do I create a presenter which has methods that handle the logic and output of the html (using content_tag, etc)?
Any general "best practices" or guidance would be appreciated. If I haven't been clear ask questions and I will respond quickly.
I'm unsure what the best practice is specifically but what I think is that making smaller view partials is the way to go so that the view code is separated and can be separately maintained. Your presentation logic resides inside a Presenter class and renders appropriate partials from app/views.
I think that using content_tag is going to make your UI designer think, say, how to add a css class to an element, ultimately leading to more maintenance time. content_tags are fine if they are smaller and are not frequently updated in terms of styling.
Another point to keep in mind is if you are a developer who is also after cleanliness of code then imagine writing a content_tag for multi-line block of <div /> with paragraph of text with multiple inner tags. You'd have to start manipulating strings to handle this and sometimes it become time consuming to yourself and other developers to follow the code.
I'm sure there are many more goodies of keeping the view template separate from Presenters but the point mentioned above is one that I learned from one of my recent projects.
When to choose a partial or helper or a loop in view.
Specifically, when we need a repeated structure only in a single page.
I would like to know which one is a best practice from DRY point of view and Performance point of view.
Thanks.
If only in a single page, as described, I would consider using a loop or partial.
- If the output is one or two lines I might just use a loop.
- If more than that a partial
If used in multiple pages I would use a helper.
Overall I prefer helpers as they feel like a more object oriented, ruby approach and they are easy and great to have tests for!
I often see, touted as one of the big benefits of ASP.NET MVC, the fact that it gets you closer to the actual page markup, as opposed to the pseudomarkup of WebForms.
If that's the case, then why does the HtmlHelper exist? It seems like all this LabelFor, TextBoxFor stuff is just as much pseudomarkup as <asp:Label> and <asp:TextBox> are in WebForms.
What am I missing? Why is there an HtmlHelper class? Do people use it in real life?
Whilst you are right in saying that HtmlHelper functions do abstract away the exact markup rendered, the big advantage of this is that the views are more DRY and you are able to pass in the necessary parameters to the functions in order to customise the HTML generated.
Rather than having to manually type out a full <input /> tag, complete with value=<%= Model.Property %>, Html.TextBoxFor is a more concise way of outputting the same thing. And as with all DRY approaches, if you need to change the HTML for all textboxes in your application (e.g. to output a new attribute) all you need to do is change the HtmlHelper method.
They seem to me a little like simple, lightweight partial views that are just designed to output some consistent HTML given some input.
The point of HTML helpers is to eliminate tedious and repetitive <input> tags.
Unlike server-side controls, HTML helpers emit raw, (fairly-)predictable HTML.
It simplifies the creation of those and allows them to be strongly named. Of course people use this!
I don't quite agree with the answers, and i somehow agree with you.
You can think of the helpers as pre-built custom controls, if you want to have some code generated you can make use of the helpers, if you want a clean approach and get closer to the html then don't.
The important point here is that MVC allows you to get close to the html, but does not limit you to only that.
You can create your own helper that created the markup you wish, and use that instead.
At the end of the day, it comes down to your own preference, and you can choose to or choose not to be closer to the html
So in my Rails application, I'm trying to set up Javascript testing on certain views.
Right now, I'm doing this by having a conditional in each view..
<% if AppConfig['js_testing'] %>
<script>
...
</script>
<% end %>
If I have it on each page, there's a lot of code duplication. Is there a way manage everything from the application layout?
There's a few places you can put this that will help reduce duplication. The main layout is an ideal candidate. Another possibility is a helper method that's a lot easier to introduce.
You could also define a conditional javascript_tag helper method that will only introduce the JavaScript if your trigger is set. Usually this is along the lines of:
def javascript_testing_tag(content)
AppConfig['js_testing'] ? javascript_tag(content) : ''
end
Then it's a pretty straightforward exercise to wrap all your test scripts with that conditional. It will make it easier to refactor things later should the logical trigger for this behavior change.
The optimal implementation depends on what kind of scripting content you're introducing. If it's tied closely to the JavaScript that may be on a particular view, you may be stuck doing this.
An alternative is to simply tag each page and have a testing JavaScript harness that will trigger specific behavior depending on the structure of the document. For example, if there's an element div#user_list you might run testUserList().
It is then trivial to simply not include the testing JavaScript file in non-testing environments.
I have heard that it's best not to actually have any html in your helpers; my question is, Why not? And furthermore, if you were trying to generate an html list or something like that, how can I avoid actual tags?
Thanks!
-fREW
My advice - if it's small pieces of HTML (a couple of tags) don't worry about it. More than that - think about partials (as pulling strings of html together in a helper is a pain that's what the views are good at).
I regularly include HTML in my helpers (either directly or through calls to Rails methods like link_to). My world has not come crashing down around me. In fact I'd to so far as to say my code is very clean, maintainable and understandable because of it.
Only last night I wrote a link_to_user helper to spits out html with normal link to the user along with the user's icon next to it. I could have done it in a partial, but I think link_to_user is a much cleaner way to handle it.
I don't see that there's anything wrong with it. The majority of the rails helpers generate HTML code (which is their purpose) - to me this implies that's what you're supposed to do yourself.
There is however the ever-present issue of code readability. If you have a helper which just builds a big string of raw HTML, then it's going to be hard to understand. While it's fine to generate HTML in helpers, you should do it using things like content_tag, and render :partial rather than just return %Q(<a href="#{something}">#{text}>)
This isn't a full answer to your question, but you can create html in your tags via the content_tag method. My guess as to why would be cleanliness of code.
Also, content_tag allows you to nest tags in blocks. Check out this blog post on content_tag.
On Rails 3 you can use *html_safe* String method to make your helper methods return html tags that won't be escaped.
As mentioned before, helpers are generally thought to be used as business logic, for doing something that drives view code, but is not view code itself. The most conventional place to put things that generate snippets of view code is a partial. Partials can call a helper if needed, but for the sake of keeping things separated, it's best to keep business in the helper and view in the partial.
Also, bear in mind this is all convention, not hard and fast rules. If there's a good reason to break the convention, do what works best.
I put html into partials usually.
Think about semantics. If you put html in a string, you lose the semantic aspect of it: it becomes a string instead of markup. Very different. For example, you cannot validate a string, but you can validate markup.
The reason I wanna put html in a helper instead of partial (and how I found this thread) is terseness. I would like to be able to write =hr instead of =render 'hr'.
To answer the question I didn't ask ;-) : to un-escape HTML in a helper, try this
def hr
raw '<hr />'
end