I want to render controller/action inside a div in Rails - ruby-on-rails

Lets say I have a 300X300px block called "Statistics" or "Friends" this block requires some database objects and logical operations that traditionally should be placed inside a controller, which prepares some instance variables that will be displayed nicely in it's view/partial.
This block could be called from many pages in my website, crossing various controllers and actions.
How can I go about this problem without repeating code inside controllers, nor placing logic inside views.
A bad solution would be to place SQL queries inside views, or using iframes where a single controller/action generates the expected HTML.
Any ideas will be greatly appreciated.

I think this is the kind of thing you should do in a helper method. It might be a good idea to use locals for you partial instead of instance variables so as not to pollute the namespace of your views:
module ApplicatonHelper
def friends_block
friends = Friend.where(...)
# Assuming the 'friends_block' partial is in a directory 'app/views/shared'
render :partial => "shared/friends_block", :locals => {:friends => friends}
end
end
The friends_block partial would use the local variable:
<div id="friends_block">
<% friends.each do |s| %>
...
<% end %>
</div>
And other views would just use the helper method without having to worry about anything else:
<%= friends_block %>

Have a look at the Cells gem:
https://github.com/apotonick/cells

I'd put the block into a partial and ensure that the required instance variables for that block are loaded in a before_filter on the relevant controllers and actions.

Related

Semi-global Rails partial

Is there a better way to achieve what I'm going for?
I have a partial in the /views/shared/ folder that has all the fields that are in a form being used to send an email.
A helper method with default options to render said partial (render partial: 'shared/email_fields' locals: locals where locals is a hash of default variables).
A helper method for every form sending an email that calls the above helper method and passes in either a FormBuilder object or a string containing the beginning of the name html attribute.
The problem I'm having: Most of the email forms differ slightly which results in me having to add additional options to the locals hash and I feel like the global partial is becoming bloated. Is there some way of using a global partial in this way such that the partial doesn't become super bloated?
I've thought of having each form completely separate but that's bad for upkeep and DRY. I've thought of passing in the name of a partial to be rendered inside the global partial but some of these forms need the same options and are rendered from different controllers and I wouldn't want to put a bunch of partials that aren't global in the /views/shared/ folder. Right now, I'm just sticking with the bloated global partial.
Any help would be appreciated!
Here's how I do it. This is going to sound weird, but bear with me.
So, I have basically two forms in my applications. For a form that submits via javascript, it looks like this:
#views/shared/_remote_form.html.haml
= form_tag #presenter.form_path,
remote: true,
id: #presenter.form_id,
class: #presenter.form_classes,
data: #presenter.form_data,
method: #presenter.form_method do
.well
= #presenter.form_inner
.form-controls-container
.form-controls-wrapper
= #presenter.form_controls
As you can see, I use presenters. The presenters are instantiated in the relevant controller as a controller variable, so that the presenter is available to the partial. Something like:
class FooController < ApplicationController
def new
#presenter = NewFooFormPresenter.new(self)
render partial: 'shared/remote_form'
end
...
end
You can see that I'm passing in the controller so that the presenter is able to render various parts of the form.
All FormPresenters inherit from FormPresenterBase that has stubbed methods for each of the methods called in the form. Something like this:
class FormPresenterBase
def initialize(controller)
#controller = controller
end
def form_path
root_path
end
def form_id
'bogus-form-id'
end
def form_classes
'something-bogus'
end
def form_inner; end
def form_controls; end
...
end
That let's me bootstrap the form without throwing a bunch of errors all the time. Naturally, that stubbed form won't really work, but that's okay because each FormPresenter will override the stubbed methods with real values. So, something like:
class NewFooFormPresenter < FormPresenterBase
def form_path
new_for_form_path
end
def form_id
'new-foo-form'
end
def form_classes
'something-not-bogus'
end
# The form fields could be unique to this form. Or, I might have a set of common
# fields that I use across multiple forms. I just decide which partial has the
# correct set of fields and render it here.
def form_inner
render partial: 'new_inner_fields'
end
# The controls are also rendered from partials. Here, I want to have an okay
# button and a cancel button. So, I just call the correct partial that
# renders those. I call html_safe on the resultant string so that it renders
# correctly.
def form_controls
[:okay, :cancel].each_with_object("") do |control_sym, to_return|
render partial: "shared/form_widgets/#{control_sym.to_s}_button"
end.html_safe
end
...
end
Of course, I can get tricky with my FormPresenters. If there are families that share common methods, I can either use further inheritance or module inclusion to keep everything DRY.
So, once I have all my basic form widgets (field combinations, controls, etc.) configured as partials, I can just mix and match in my presenter to my heart's delight. And (at least for forms), I basically never have to write another partial for the rest of my life. Whenever I need a new variant, I just spin up a new FormPresenter and customize it to give me the form I desire.
Actually, there's a little bit more to it than all of that, but hopefully this gives you a sense of another way to skin the cat.
An approach is to have a separate partial for each form. Take all of the items the forms have in common and put them in a partial. You can then reference the "common items" partial within your individual form partials. Depending on how your forms are structured, you may have several "common items" partials, but that is okay. The goal is to keep the code organized and DRY.

What is the difference between render and yield in Rails

Can someone explain the difference between "<%= render %>" and "<%= yield %> with <% content_for :partial do %>/<% end %>"? specifically how the routing changes when switching from one to another, the benefits of using one over the other, when is it practical to use one over the other. THIS is the closest explanation I have found, but isn't quite clear enough for me.
I have been trying for several days to wrap my head around this, but it seems that each configuration I try either comes close, or errors out.
If theres are three views, aaa and bbb and ccc, and each has an index.html.erb, but bbb and ccc have a _content.html.erb partial (signified by the underscore) how can you accomplish getting the bbb or ccc partial in aaa using either render or yield?
The following works:
aaa's index.html.erb :
<div">
<%= render 'bbb/content' %>
</div>
and bbbs _content.html/erb :
<p>Content from bbb.</p>
BUT this does NOT:
aaa's index.html.erb :
<div">
<%= yield :container %>
</div>
and bbbs _content.html/erb :
<% content_for :container do %>
<p>Content from bbb.</p> ### viewed in aaa
<% end>
and cccs _content.html.erb would have nothing, or the content_for, but I still dont get aaa's index.html to be populated with content.
If I use the render, I can explicitly place the content in. But I thought that the benefit of using the yield :whatever would allow me to choose what to populate it with, and I can't get it to populate anything as soon as I change it from render to yield. Do I also have to update the routes file? If so, how do I choose which one to populate it with? Does that mean its in the controller? and needs an action?
I also have though that it depends on which file is initially routed to, but like I said, I think I need to understand the difference between the two before I can begin to use the partials to my advantage.
First of all, yield is ruby, render is rails. Usually one uses a common layout for the application whose inner content changes according to action/context. The problem usually lies in defining where our layout ends and context-specific template begins. Take, for instance, the HTML title tag. Let's say you have an application called Cities. In most cases, you want your page title to be "Cities" all the time. But, if you're for instance, inside Amsterdam page, then you would like the have "Amsterdam" as your page title.
# application.html.erb
<html>
<head>
<%= content_for?(:page_title) ? yield(:page_title) : "Cities" %>
......
# city/index.html.erb
<% content_for :page_title do %>
<%= #city.name %>
<% end %>
<div class="bla"...
Within Rails you usually define your application title in your application layout. One strategy for changing the page title would be to use content_for in the specific cities template and change accordingly.
Render, on the other hand, accomplishes different rendering strategies. Straight. When you call render, it renders. content_for/yield doesn't render automatically, it is stored somewhere and then fills up the missing spots in the due places. So, you can think of it as more as a "store/search/replace" in comparison to render, which just plain renders.
Good rule of thumb to use one over the other is: if the template you are writing needs to present different information per context, strongly consider using content_for.
yield
Ruby code (Proc class) and takes your block and does what it is supposed to do with it. Yield is also fast compared with other Ruby based ways of doing the same thing.
I'd assume (and I only) use it in the layouts because it's quick and I mindlessly do what's normal in Rails. yield is also used to pass content to a specific spot in your layout. I often have <%= yield :head %> in the head, just above the head tag, so that I can pass random weirdness that sometimes comes up.
Common Uses:
Mostly just used in layouts
(if you are fancy/inclined to do so in a Model) as a true Ruby Proc
statement.
render
Rails code that you pass arguments to that, as the docs say, "Renders the content that will be returned to the browser as the response body". partials, actions, text, files...etc.
Common Uses:
Used in both views and the controller.
When your controller method exits, it renders the associated file. So the edit controller renders edit.html.erb. It uses the specified layout or application.html.erb if none is specified.
Within your layout file, when you call yield it will fill in the information from your render. If you call yield with a parameter, it will look for a content_for section in your render file matching that parameter. I'm not completely sure, but I don't think you can call yield from outside of your layout file, and I don't think it will fill in any information except that found in your render file.
Anywhere in your layout file or your rendered file, you can render a partial by calling render with the partial name minus the underscore.
I hope that helps.
Edit to answer question in comment:
yield and render perform similar functions however yield only looks in the render file whereas render specifies which file to render. Also, render outputs the entire file, but yield with a parameter can output just a subsection of the file.
Here's a visual to put them both in perspective:
The render method is called at the end of a controller action and orchestrates what block is passed to the method that is actually rendering the application.html.erb by yielding the passed block.
https://richstone.io/debunk/

Using Rails helpers to render partials

From my understanding, helpers are mainly used to clean up views from some view-specific logic.
But on my currently new project (legacy application), I've stumbled upon a lot of helpers that look like this
def itemprepare
render :partial => 'items/itemlist_summary'
end
Is this correct? Rendering a partial to me seems like something you would want to do in the view, as it doesn't include any logic that needs to be abstracted.
Should I just inline all of these helpers?
Rendering a partial doesn't belong in a helper. Helpers should help you to do things that contain logic. Logic doesn't belong in the controller unless it's logic to render partials and decide if something should be displayed or not.
Although you generally shouldn't use helper methods to render partials, I can see how in some situations that might be necessary. For those circumstances, you need to use the concat method:
def itemprepare
concat(render(:partial => 'items/itemlist_summary'))
end
Like Ajedi32 says, partials use belongs to views but sometimes it's useful to use them in helpers. I hope it's useful to show what I've done in my application:
I've been following the excellent article Thinking of Rails Helper to help DRY our view. I'm using Jquery Mobile with a fixed header, nav-bar, navigation panel and a footer.
In every page I need to include the footer and the navigation panel, so usually it would have been:
<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /footer -->
<%= render "shared/nav_panel" %>
</div><!-- /page -->
at the end of each page.
Then I refactored the render partial into the application helper and now it is:
# app/helpers/application_helper.rb
def page_footer
footer = content_tag :div , :"data-role" => "footer" do
content_tag :h4, "Page Footer"
end
nav_panel = render(:partial => 'shared/nav_panel')
footer + nav_panel
end
and in the view I just call:
<%= page_footer %>
This is just a short example; in reality the app has a footer that changes according to the logged-in status, user language, etc..
We have a couple of helpers like that in our project, but most of them are in our custom gem. Wrapping partial rendering with helper prevents application from knowing how the information is rendered and we can easily extend logic, change partial, or do whatever we want inside this helper as long as it renders requested part of the view. Sometimes these partial require some data that resides inside the gem itself and there is no need to expose it to application. So application calls helper method (sometimes without any parameters at all) that forms required parameters and locals and passes them to partial.
But when you're just rendering partial inside your application and you don't need any extensive logic around that rendering I don't think there's much use from creating new helper for every partial.

How can I create a "partial" that has its own action?

In my rails application, I render a partial on multiple pages, and in that partial is a variable. So currently, lets say I have 5 pages that render :partial => "partialname", and inside of partialname is #variable.
Can I have it so that partialname has its own action with #variable instantiated inside, rather than having #variable be called 5 times from each action that renders the partial?
Thanks!
I would create a before_filter on all the methods that need the common behavior.
But if you really want the partial to have its own "action," make a helper method that does whatever "action-y" things you want and then renders the partial. That works out to essentially the same thing. I've done this before to make a template-type partial that contains various pieces of data that need processing.
Rails Sub-controllers?
See my answer on this.
Very similar method here, using before filters either using controller inheritance or modules when needed.
So, is this a problem of code running 5 times per request that you'd rather not? Like, you've got a partial and in it is:
#my_var = MyModel.some_expensive_method
If so, you could just cache the result in the model:
def cached_some_expensive_method
#some_expensive_method ||= some_expensive_method()
end
you could load #variable from the view:
&lt% #variable = Variable.find(:whatever) %>
but some consider this bad practice in not adhering to strict MVC. This does have the benefit of supporting fragment caching out of the box:
&lt% cache({:variable_id => :whatever}) do %>
&lt% #variable = Variable.find(:whatever) %>
. . .
&lt% end %>
Is there a common model that's being rendered in the main views that you could delegate the variable access to?
&lt%=h #model.variable %>

How do I implement Section-specific navigation in Ruby on Rails?

I have a Ruby/Rails app that has two or three main "sections". When a user visits that section, I wish to display some sub-navigation. All three sections use the same layout, so I can't "hard code" the navigation into the layout.
I can think of a few different methods to do this. I guess in order to help people vote I'll put them as answers.
Any other ideas? Or what do you vote for?
You can easily do this using partials, assuming each section has it's own controller.
Let's say you have three sections called Posts, Users and Admin, each with it's own controller: PostsController, UsersController and AdminController.
In each corresponding views directory, you declare a _subnav.html.erb partial:
/app/views/users/_subnav.html.erb
/app/views/posts/_subnav.html.erb
/app/views/admin/_subnav.html.erb
In each of these subnav partials you declare the options specific to that section, so /users/_subnav.html.erb might contain:
<ul id="subnav">
<li><%= link_to 'All Users', users_path %></li>
<li><%= link_to 'New User', new_user_path %></li>
</ul>
Whilst /posts/_subnav.html.erb might contain:
<ul id="subnav">
<li><%= link_to 'All Posts', posts_path %></li>
<li><%= link_to 'New Post', new_post_path %></li>
</ul>
Finally, once you've done this, you just need to include the subnav partial in the layout:
<div id="header">...</div>
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>
Partial render. This is very similar to the helper method except perhaps the layout would have some if statements, or pass that off to a helper...
As for the content of your submenus, you can go at it in a declarative manner in each controller.
class PostsController < ApplicationController
#...
protected
helper_method :menu_items
def menu_items
[
['Submenu 1', url_for(me)],
['Submenu 2', url_for(you)]
]
end
end
Now whenever you call menu_items from a view, you'll have the right list to iterate over for the specific controller.
This strikes me as a cleaner solution than putting this logic inside view templates.
Note that you may also want to declare a default (empty?) menu_items inside ApplicationController as well.
Warning: Advanced Tricks ahead!
Render them all. Hide the ones that you don't need using CSS/Javascript, which can be trivially initialized in any number of ways. (Javascript can read the URL used, query parameters, something in a cookie, etc etc.) This has the advantage of potentially playing much better with your cache (why cache three views and then have to expire them all simultaneously when you can cache one?), and can be used to present a better user experience.
For example, let's pretend you have a common tab bar interface with sub navigation. If you render the content of all three tabs (i.e. its written in the HTML) and hide two of them, switching between two tabs is trivial Javascript and doesn't even hit your server. Big win! No latency for the user. No server load for you.
Want another big win? You can use a variation on this technique to cheat on pages which might but 99% common across users but still contain user state. For example, you might have a front page of a site which is relatively common across all users but say "Hiya Bob" when they're logged in. Put the non-common part ("Hiya, Bob") in a cookie. Have that part of the page be read in via Javascript reading the cookie. Cache the entire page for all users regardless of login status in page caching. This is literally capable of slicing 70% of the accesses off from the entire Rails stack on some sites.
Who cares if Rails can scale or not when your site is really Nginx serving static assets with new HTML pages occasionally getting delivered by some Ruby running on every thousandth access or so ;)
You could use something like the navigation plugin at http://rpheath.com/posts/309-rails-plugin-navigation-helper
It doesn't do sub-section navigation out of the box, but with a little tweaking you could probably set it up to do something similar.
I suggest you use partials. There are a few ways you can go about it. When I create partials that are a bit picky in that they need specific variables, I also create a helper method for it.
module RenderHelper
#options: a nested array of menu names and their corresponding url
def render_submenu(menu_items=[[]])
render :partial => 'shared/submenu', :locals => {:menu_items => menu_items}
end
end
Now the partial has a local variable named menu_items over which you can iterate to create your submenu. Note that I suggest a nested array instead of a hash because a hash's order is unpredictable.
Note that the logic deciding what items should be displayed in the menu could also be inside render_submenu if that makes more sense to you.
I asked pretty much the same question myself: Need advice: Structure of Rails views for submenus? The best solution was probably to use partials.
There is another possible way to do this: Nested Layouts
i don't remember where i found this code so apologies to the original author.
create a file called nested_layouts.rb in your lib folder and include the following code:
module NestedLayouts
def render(options = nil, &block)
if options
if options[:layout].is_a?(Array)
layouts = options.delete(:layout)
options[:layout] = layouts.pop
inner_layout = layouts.shift
options[:text] = layouts.inject(render_to_string(options.merge({:layout=>inner_layout}))) do |output,layout|
render_to_string(options.merge({:text => output, :layout => layout}))
end
end
end
super
end
end
then, create your various layouts in the layouts folder, (for example 'admin.rhtml' and 'application.rhtml').
Now in your controllers add this just inside the class:
include NestedLayouts
And finally at the end of your actions do this:
def show
...
render :layout => ['admin','application']
end
the order of the layouts in the array is important. The admin layout will be rendered inside the application layout wherever the 'yeild' is.
this method can work really well depending on the design of the site and how the various elements are organized. for instance one of the included layouts could just contain a series of divs that contain the content that needs to be shown for a particular action, and the CSS on a higher layout could control where they are positioned.
There are few approaches to this problem.
You might want to use different layouts for each section.
You might want to use a partial included by all views in a given directory.
You might want to use content_for that is filled by either a view or a partial, and called in the global layout, if you have one.
Personally I believe that you should avoid more abstraction in this case.

Resources