Use cases for the different Padrino haml helpers - ruby

I read http://www.padrinorb.com/guides/application-helpers but I'm unclear as to what are the use cases for each of the view helpers. Specifically, how do content_for/yield_content, render/partial, capture_html, and concat_content all fit together?
Right now I've been using render 'my/view' in my controllers and throwing in some =partial 'my/partial' within 'my/view' just to break apart the main template file into smaller chunks.
Is the right way to go about it? And when/where would I want to use the other helper functions?

Let's go through the use cases.
content_for/yield_content
This is for injecting content into a layout file that might be useful. Example is adding additional css/scripts into a layout from another template. The example on the guide is the same, showing how to add CSS files to your layout from any template that requires them. You can also use it for adding content onto sidebars, additional links, etc. It is for things that do not require their own template but need to pass information back to a layout based on the view being shown.
render/partial
render is for showing a given template associated with a route. render should be used for the main actions after a route is processed. partial is like a 'method' in a view. It can be reused and variables can be passed to change the output. You use partials in main templates to break up code and reuse pieces of views that otherwise might seem redundant.
capture_html/concat_content
This is usually used to create your own helpers that take blocks of content. For instance let's create a helper that takes a haml block and wraps it in a div. Usage is as follows:
# template.haml
# NOTE the equals so the content is returned
# and added to the view directly
= div_wrapper do
%h1 Some heading
%p This is now wrapped in a div
To implement this and use it in a template, you need to be able to 'capture' the haml passed into the block in order to process and then wrap a div around it. This is where capture_html comes in:
def div_wrapper(&block)
nested_content = capture_html(&block)
content_tag(:div, nested_content)
end
This will take the content and spit it out into the view wrapped in a div. Now, lets presume we want this helper to be more complex and so you want the use to be more like this:
# template.haml
# NOTE the dash so the content is not outputted directly
- div_wrapper do
%h1 Some heading
%p This is now wrapped in a div
but it also works in other helpers:
# some_helper.rb
def example(name)
div_wrapper { "<h1>Test</h1>" }
end
In order to properly print out the wrapped content from the helper in both a template AND straight ruby, we can use concat_content and check to see if we need to 'concat' the result to the template or simply return it.
def div_wrapper(&block)
nested_content = capture_html(&block)
tag_result = content_tag(:div, nested_content)
block_is_template?(block) ? concat_content(tag_result) : tag_result
end
I hope this works as a basic overview. The functions can overlap but generally it becomes clear when to use which based on specific context.

Related

Execute Ruby method on whole page in Middleman

On my Middleman-built website, I need to execute specific Ruby code on the contents of all the pages (templates).
For example, if I had following helper in my config.rb:
def myexample(text)
text.gsub("dog","cat")
end
And in my test.html.haml:
= myexample("Some text about a dog.")
My previewed and generated /test.html would read:
Some text about a cat.
However, I am using several different ways to output text that needs to be modified, most notably through HAML's :markdown filter, so I would prefer not to wrap everything in the = myexample("Text") helper.
I would like to be able to run Ruby code that would take contents of all the pages (preferably) or generated HTML output (if the first option is not possible) as an argument passed to such helper.
Ideally, this code would be run in both the development and build environments, but if that's not possible, build is enough.
Is it possible to do so?
PS. In my specific case, I use a shorthand notation to reference other pages and then I use a regular expression and eval() in order to replace them with relative links from data files.
ActionController::Base has the render_to_string method which will give you the normal HTML output from rendering a partial or page, but in string format. This would allow you to grab the rendered HTML and modify it before finally rendering it for real as an inline template.
In your controller:
rendered_html = render_to_string 'your_template_or_partial'
# do stuff to rendered_html
render inline: rendered_html.html_safe, layout: 'layouts/application'
The html_safe method makes sure Rails knows it's safe to render this as HTML. You do NOT want to do this if user input is being rendered and you have not sanitized it!!!!
If you don't want it to use a layout when rendering, just remove the :layout argument.

Block asp.net mvc Html creation in using scope

I use an HTML helper that returns an IDisposable to create a specific DIV structure that I need very often in my application. The constructor of this class creates the open divs while the Dispose method created to closing Divs. Now I need to secure my application and I would like this structure not to be created in some condition but I also need that every kind of HTML that this produced between using and the end if its scope is also not rendered.
First thing I did was to replace the TextWriter found int he ViewContext with dummy :
_helper.ViewContext.Writer = new StringWriter(new StringBuilder());
Its working for each piece of code that directly uses the ViewContext Writer to render HTML but not for the others (raw HTML and other helper)
So the question is : How can we prevent a Asp.net view to render HTML within the scope of a using block ?
I am afraid that currently there's no way of preventing the contents of a using block to be rendered. That was not the original intent of this block anyway. If you want to prevent something from being rendered you might consider using an if statement instead.
I have no example code for you, and this idea is pretty hackish but may work if you have a zillion of these things you need to secure and don't have time to add condition logic.
What if you used the app's Response.Filter to strip out html? Then in your constructor and dispose methods, if the user isn't authorized to see the content, output some easy to find elements that you could either regex replace or use Html Agility Pack to parse/modify the DOM before the stream is sent to the browser.

Yii difference between rendering functions

I sometimes get messed up by the three rendering methods:
Controller::render()
Controller::renderPartial()
Controller::renderFile()
Please could you explain. Thank you!
render() is commonly used to render a view that corresponds to what a user sees as a "page" in your application. It first renders the view you have specified and then renders the layout for the current controller action (if applicable), placing the result of the first render into the layout. It then performs output processing (which at this time means automatically inserting any necessary <script> tags and updating dynamic content) and finally outputs the result.
renderPartial() is commonly used to render a "piece" of a page. The main difference from render() is that this method does not place the results of the render in a layout. By default it also does not perform output processing, but you can override this behavior using the $processOutput parameter.
renderFile() is a low-level method that does the grunt work of rendering: it extracts the data variables in the current scope and then runs the view code. The other two methods internally call this one, but you should practically never need to call it yourself. If you do, keep in mind that you need to pass in a file path (not a view path).
Render File:
Will run the rendering methods on a given file with the set rendering engine. This is fairly low level within Yii and only really used internally or in console commands.
Render Partial:
This takes the alias given and converts it into a file path using all the local variables such as current running controllers and modules and alias definitions. It then pretty much just uses render file.
Render:
This is combination of render partials to make our lives easier. It will render the layout on the currently active contoller, or the defined one, render all the content within it, handle caching of renders, and process the output for client scripts.
Hope that clears it up.
renderPartial() is really useful for displaying ssi components in a page - ie, headers, footers, widgets etc.

HTML in public folder with hooks

I have an HTML file (index.html) in the public folder.
These HTML has some "hooks" in it.
Like:
<div>{client_ssnumber}</div>
<div>{client_company}</div>
I have to retrieve this file and complete the information in the hooks using data obtained in a controller´s method, then display in the screen.
What is the rails way to do it?
You can't do this (without terrible terrible hacking), it's hard coded to look for public files before checking the router.
Anyway, Your client is wrong. Tell them to use "<%= ... %>" instead of "{ ... }" and move it into a view (you should move it into the view, so it's where you want it to be, then just tell them what the name of the file is).
There is no sensible reason to make up your own templating language. It will be buggier and slower, and it will add a lot of time to get the product out the door. Plus you'll then have to maintain that code. This is a solved problem, use ERB. If they really like that syntax, use Mustache which is pretty similar, and is an existing templating language.
If you can't get them to do this, you have much bigger problems than how to render this page.
Put them in a view, on app/views/ and use a template engine like erb or haml. You can then assign variables in a controller and use them in your view.

How to render partials from unrelated controllers in one view....almost Amazon style

How can we render many partials from different controllers into one view?
The local variables of each partial are calculated separately in different and independent controllers.
What I really have to make things more specific, is a home layout, and in that layout that has dynamic content, there's a partial that only handles site wide news announcements, and these are independently updated.
I know a quick hack such like:
render :partial => '/news', :locals=> {#news = News.last}
but I want something more "correct". Like I've been reading about :templates rendering but i'm not sure how it works exactly in Rails 3.1.
Any help would be highly appreciated!
2.2.3 Rendering an Action’s Template from Another Controller
What if you want to render a template from an entirely different controller from the one that contains the action code? You can also do that with render, which accepts the full path (relative to app/views) of the template to render. For example, if you’re running code in an AdminProductsController that lives in app/controllers/admin, you can render the results of an action to a template in app/views/products this way:
render 'products/show'
Rails knows that this view belongs to a different controller because of the embedded slash character in the string. If you want to be explicit, you can use the :template option (which was required on Rails 2.2 and earlier):
render :template => 'products/show'
Sources: http://guides.rubyonrails.org/layouts_and_rendering.html#using-content_for
Should have read in more details.

Resources