Can a rendered partial observe local variables? - ruby-on-rails

i have a shared template that i use regularly to show errors like :
<%= render "shared/flash_error", :error => flash[:error], :info => flash[:info] %>
This variables are optional, so my view is like :
<% if defined?(error) and error %>
<div class="error">
<%= error %>
</div>
<% end %>
<% if defined?(info) and info %>
<div class="info">
<%= info %>
</div>
<% end %>
Now, there are cases when i would need to add a new optional variable and extend the partial with other types of errors. This, however, can make the rendering hard to keep up with. I would now need to edit every render and change it to :
<%= render "shared/flash_error", :error => flash[:error], :info => flash[:info], :new_entry => flash[:new_entry] %>
and so on with every new entry. So, i am wondering, is there a way for the rendered partial to 'observe' specific flash variables,so that i don't even have to pass them as attributes to the rendered view ?

Yeap, tried it and works fine. Something like :
<%= render "shared/flash_error", msg_notifications %>
where msg_notifications is just a hash filled with everything, so it can be changed in a DRY way. Simple, yet sometimes the mind plays bad games :P

Related

check if Rails partial is empty

I have a main page that is responsible for HTML/CSS styling, but some of the contents come from partials. A partial receives some locals or params, i.e. current_user or person, and displays information if any.
Is there a way for me to check if a partial rendered anything? My end goal is something like this:
<% if my_partial can render something %>
<div class="css_for_something">
<%= render(partial: 'my_partial', locals: {...} ) %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
<% end %>
I do not want the partials to handle styling logic; they just need to display content if any. Conversely, the main page should not know anything about the logic in the partial(s), such as checking values or querying the database.
Thank you
Unfortunately, Chris Peter's solution did not work for me on rails 4.2.4, as render_to_string seems to not be available in views.
However, the following worked (rails 4.2.4):
<% partial_content = render partial: 'my_partial' %>
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<%# rendered if partial is empty %>
<% end %>
Be aware that the present? check really only checks if what was rendered is empty. If, something, e.g. a HTML comment, is returned, the check returns false.
Try storing the value generated by render_to_string in a variable:
<% partial_content = render_to_string(partial: 'my_partial', locals: {...} ).strip %>
Then you can see if it contains any content:
<% if partial_content.present? %>
<%= partial_content %>
<% else %>
<div class="css_for_no_info">
<%= render something else %>
</div>
<% end %>

Render rails partial multiple times on same page

I have a partial that I'm rendering twice on the same page, but in two different locations (one is shown during standard layout, one is shown during mobile/tablet layout).
The partial is rendered exactly the same in both places, so I'd like to speed it up by storing it as a variable if possible; the partial makes an API call each time, and the 2nd call is completely unnecessary since it's a duplicate of the first API call.
Is there any way to store the HTML from the returned partial as a variable and then use that for both renders?
Edit: I'm hoping to do this without caching, as it is a very simple need and I'm looking to keep the codebase lean and readable. Is it possible to store the partial as a string variable and then reference that twice?
<% content_for :example do %>
<%= render :your_partial %>
<%end%>
then call <%= yield :example %> or <%= content_for :example %> wherever you want your partial called.
One option would be to use fragment caching. After you wrap the partial with a cache block, the second call should show the cached version of the first. For example:
<% cache do %>
<%= render(:partial => 'my_partial') %>
<% end %>
... later in the same view ...
<% cache do %>
<%= render(:partial => 'my_partial') %>
<% end %>
To store the result of the render to a string, you could try the render_to_string method of AbstractController. The arguments are the same as for render.
partial_string = render_to_string(:partial => 'my_partial')
I'm adding an answer to this old question because it topped Google for a search I just made.
There's another way to do this now (for quite a while), the capture helper.
<% reuse_my_partial = capture do %>
<%= render partial: "your_partial" %>
<% end %>
<div class="visible-on-desktop"
<%= reuse_my_partial %>
</div>
<div class="visible-on-mobile"
<%= reuse_my_partial %>
</div>
This is simpler and slightly safer than using content_for because there is no global storage involved that something else might modify.
The rails docs linked to use instance #vars instead of local vars because they want it to be available to their layout template. That's a detail you do not need to worry about, because you're using it in the same template file.

Rails 3, partials, optional arguments - is this best way to do this?

Migrating app from php. and have this in the view:
<%=render :partial => "jt-test", :locals => {:info => "here is my info", :hide_location=>true} %>
<br /><br />
<%=render :partial => "jt-test", :locals => {:info => "here is my info"} %>
in _jt-test.html.erb:
My info:<br />
<%=info %>
<% if local_assigns.has_key? :hide_location %>
you want to hide location!
<% end %>
Is the local_assigns the proper / best way to do this? Can I have an unlimited number of local_assigns? Is there a local_assigns for the main view called from the controller?
thx
In the main view you'd just use normal action class variables (#whatever_variable_name), and they're assigned in the controller:
class FoosController
def index
#foos = Foo.all
end
end
# template
<% #foos.each |foo| %>
<%= foo.name %>
You may have unlimited locals in a partial, but if there are a "lot", you might be doing it wrong. consider using an encapsulating object, breaking up the template more, etc.
Rails exposes local variables to partials by their name (info and hide_location in your case). You don't need to look it up using has_key?. See the passing local variables docs in the layout and rendering guide.
Rails 3 improves the way you can render partials.
<%= render "jt-test", :info => "here is my info", :hide_location => true %>
<br /><br />
<%= render "jt-test", :info => "here is my info", :hide_location => false %>
in _jt-test.html.erb:
My info:<br />
<%= info %>
<% unless hide_location %>
you want to hide location!
<% end %>
Is the local_assigns the proper / best way to do this?
The above is the preferred way of rendering partials with Rails 3
Can I have an unlimited number of local_assigns?
You're limited by memory.
Is there a local_assigns for the main view called from the controller?
Not sure but why would you want to do that. Keep view logic out of the controllers.
Like Dave said, if you have a lot of optional variables, you might be better off encapsulating an object and passing it to the partial, but in the case of checking for optional local assigns, the has_key? method is the best way to go.

Rails - Passing an option variable in a partial

I'm building a header partial for a view. I call the partial as following:
<%= render :partial =>"project/header", :locals => {:right_header => 'BLAH BLAH'} %>
The header has a default right_header, but I'd like the option to overwrite it:
<div id="header">
<span class="right">
Standard Header here
</span>
</div>
The deal is when calling the partial, right_header won't always be defined, I'd like for it to be optional, but that's where I'm struggling and rails keeps erroring... In the partial I've been trying:
<% if right_header.empty? %>
default header....
<% else %>
<%= right_header %>
<% end %>
Suggestions? Am I passing this correctly to the partial with locals?
Thank you
use
if defined? right_header
another way is
right_header ||= 'default'
in the view. so if right_header is not passed in, its value will be default. You can pass in any value too, and later on just do things according to the value of right_header.

What's the cleanest way to add a class attribute to an html element in a view in rails

I'm writing some Rails code for a partial view, and I want it to only show a comment field if somebody is already logged onto a site here.
If the page is viewed by someone who isn't a member of the site yet, the shared/comment_not_logged_in fragment should be passed in.
However, I'm totally stumped as to why I can't run the same check to decide if the page should add the class attribute "missing_your_voice" to the enclosing div element here:
<li class="user_submission_form bubble comment_form <% "missing_your_voice" if not current_user %>">
<% if current_user %>
<%= image_tag(current_user.avatar(:comment), :class => "profile_pic") %>
<% form_for [parent, Comment.new] do |f| %>
<%= render "comments/form", :f => f %>
<% end %>
<% else %>
<%= render :partial => 'shared/comment_not_logged_in' %>
<% end %>
</li>
The same idiom, "missing_your_voice" if not current_user returns the string in irb, and also in the console debugger.
What am I doing wrong here?
You forgot an =. Replace <% by <%=, so that you get:
<%= "missing_your_voice" if not current_user %>
Remember that <% ... %> will only run Ruby code, but not display anything. Using <%= ... %> will run the code and display the result of the expression.
As molf already pointed out, there's a missing = on your view.
It should be <%=.
Other than that, be sure to make your controller method available to your view by calling helper_method in your controller.
Take a look on the documentation if needed.

Resources