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.
Related
I am new to caching and I'm not sure what my best course of action is.
I want to cache a part of my view that relies on a complex query. The query looks something like:
#sessions_next_week = group_by_wday(LittleClassSession.location_only([1,2]).age_range_only(age_from, age_to).supports_dropins_only(support).approved_users_only.next_week)
Above you'll see a number of scopes and methods called. The view renders an instance variable named #sessions_next_week like so:
<% #sessions_next_week.each do |wday, lcs| %>
<h3><%= wday %></h3>
<%= render partial: 'table_head' %>
<% lcs.each do |s| %>
<%= render partial: 'table_row', :locals => {:s => s, :show_day => true} %>
<% end %>
<%= render partial: 'table_foot' %>
<% end %>
As you can see, #sessions_next_week is iterated through, and its children are iterated through. Given this, and given the nature of the query results in the instance variable, I'm not sure where to implement the caching. In the model? In the view?
So my questions are:
Do I need model caching or can I do this in the view?
What's the correct implementation?
The solution is to simply add two character:
#sessions_next_week ||= group_by_wday(LittleClassSession.location_only([1,2]).age_range_only(age_from, age_to).supports_dropins_only(support).approved_users_only.next_week)
This is called memoization, and you can look it up. Here's one source: http://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/
I have a resource called Exercises in my application. I currently have a partial called _exercise.html.erb that I use to render them. I have an outlying case where I'd like to render them in a much different way. Can I make another partial for exercises that has this other format and still be able to use <%= render #exercises %>?
If not what is the best approach? Should I out a variable in the controller that tells the partial which layout to use, this would have both layout in one file and one if to decide. Or is there some better way?
If you'd like to use business logic to determine when to show what partial for your #exercises collection you should use the to_partial_path method in the Exercise model to define that. See #4 in this post: http://blog.plataformatec.com.br/2012/01/my-five-favorite-hidden-features-in-rails-3-2/
Or, if this is more of a view-related decision (i.e. one view will always use the regular _exercises.html.erb and another view would always use e.g. _alternate_exercises.html.erb) then you can specify as such:
<%= render partial: 'alternate_exercises', collection: #exercises, as: :exercise %>
This will render the _alternate_exercises.html.erb partial once for each item in #execrises passing the item in to the partial via a local_assign called exercise.
In this case, I suppose you have two options:
1) Put the conditional code inside of _exercises.html.erb
eg.
<% if #exercise.meets_some_condition %>
you see this stuff
<% else %>
you see other stuff
<% end %>
This way, you can still make use of <%= render #exercises %>
2) Otherwise, your other option is to have separate partials and render them outside.
eg.
<% #exercises.each do |exercise| %>
<% if exercise.meets_some_condition %>
<%= render "exercises/some_condition_exercise" %>
<% else %>
<%= render "exercises/exercise" %>
<% end %>
<% end %>
This is the best approach for rendering partial. You can wrap that partial with if else statement in your code. Here is my example
rendering with form called _victim.html.erb
<%= render :partial => "victim", :locals => {:f => f }%>
rendering without form
<%= render :partial => "victim"%>
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.
I have a different subheader partial I want to render dependent on where I'm at in my application. How do I go about determining where I'm at via ruby? Or do I need to parse the URL?
Example :
If I'm at my root level I want to use /home/subheader, if I'm in controller 'test' I want to render /test/subheader, etc... etc...
basically looking for this part:
(in my application view)
<%- if ############ %>
<%= render :partial => '/home/subheader' %>
<%- elsif ########### %>
<%= render :partial => '/test/subheader' %>
<%- else %>
<%= render :partial => '/layouts/subheader' %>
<%- end %>
Thanks
You can use current_page?
if current_page? :controller => 'home', :action => 'index'
do_this
end
or use the controller's method controller_name
if controller.controller_name == 'home'
do_that
end
If you're using this in a per-controller basis, you should probably need layouts or use different templates, rendering different partials depending in controller/action is a code smell.
P.S: You could also try to get the params[:controller] and params[:action] variables, but I am not sure if they are passed correctly if your route is non the standard /:controller/:action
A slightly easier way to manage this would be to use content_for. For example:
#app/layouts/application.html.erb
<html>
<body>
<h1>My Application</h1>
<%= yield(:subheader) || render(:partial => 'layouts/subheader') %>
<%= yield %>
</body>
</html>
This layout will first try to render the subheader content that was passed in from the view, otherwise it will render the partial 'layouts/subheader'. Then in each view that requires a custom subheader, all you have to do is:
#app/views/home/index.html.erb
<% content_for :subheader, render(:partial => 'subheader') %>
And in your other controller, you could use something completely different, like:
#app/views/other/show.html.erb
<% content_for :subheader do %>
<h2>A different subheader</h2>
<% end %>
I have the following in a view (.html.erb) :
<% #posts = GetAllPostsFunctions %> (removed for berivity)
<% #posts.each do |post| %>
<%= post.title %>
<%= render :partial => "posts/post_show" %>
<% end %>
the posts_show partial has the following:
....
<td><%=h #post.title %> </td>
But I get the following error
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.title
Any ideas?
You can also simply things by using the :collection for render :partial. Which pass each item in the value for :collection to a local variable sharing the name of your partial.
<% #posts = GetAllPostsFunctions %> (removed for berivity)
<%= render :partial => "posts/post_show", :collection => #posts %>
In this case, Rails will render post_show for each item in #posts with the local variable post_show set to the current item. It also provides handy counter methods.
Successfully using this approach would require renaming the app/views/posts/_post_show.html.erb partial to app/views/posts/_post.html.erb to or changing every occurance of post in your partial to post_show. If you renamed the partial to the conventional _post.html.erb which will then allow you to simply do:
<%= render :partial => #posts %>
Which will render the partial for every single post in the #posts variable.
Since the post variable in the each loop is a locale variable you have to make it available to the partial:
<%= render :partial => "posts/post_show", :locals => {:post => post} %>
You can then access the title through the local variable post:
<td><%=h post.title %> </td>
You could also simplify the whole thing by rendering the posts as collection. Take a look at the Rails documentation for more information:
http://api.rubyonrails.org/classes/ActionController/Base.html#M000658
It doesn't look like you're setting the #post of the partial, so when it goes to evaluate the partial it gets a null reference.
Alternately, ensure that your post fetching functions are actually returning something
I'm not positive, but I think in the partial you have to do post.title not #post.title
Sorry if I misunderstood you, I'm new to rails.