create instance variable in erb template - ruby-on-rails

Say I have 2 erb views: a list view and a show view, I want to render the show view inside the list view
list view
<% #vehicles.each do |vehicle| %>
<h2><%= vehicle.type %></h2>
<ul>
<% vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
<% end %>
show view
<h2><%= #vehicle.type %></h2>
<ul>
<% #vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
the issue is the show view takes an #vehicle instance variable, how can I pass that down from the parent if I was going to nest these and it still shows up as an instance variable, accessed with #vehicle? something like:
<% #vehicles.each do |vehicle| %>
<%= render "show" %>
<% end %>

I guess you might want to make that show view a partial. Something like:
<h2><%= vehicle.type %></h2>
<ul>
<% vehicle.accessories.each do |accessory| %>
<li><% accessory.title %></li>
<% end %>
</ul>
Then you can do something like:
<% #vehicles.each do |vehicle| %>
<%= render "path/to/show_partial", locals: {vehicle: vehicle} %>
<% end %>
Naturally, you'll want to:
use the real path/to/show_partial, whever that happens to be, and
do some eager loading so that you're not doing a whole bunch of N+1 queries.

Related

How to handle a Rails query causing massive delays

So I'm using the query below that is then being used as a submenu and it's causing significant loading issues. I've put it in the application_helper for the time being.
def category_level
Connector::Category.includes(:products).group_by(&:parent_category_id)
end
Then it's being displayed on the home page with the following:
<ul class="list-style-upper">
<% category_level[nil].each do |root| %>
<%= render 'products/submenu/category_item', category: root %>
<% end %>
</ul>
Which redirects to
<li class="list-one">
<%= category.name %><p><%= category.products.count %></p>
<% if category_level[category.id].present? %>
<ul class="list-style-upper-sub">
<% category_level[category.id].each do |child| %>
<%= render 'products/submenu/category_item', category: child %>
<% end %>
</ul>
<% end %>
</li>
The issue is that there are typically around 30,000 products. Is there a way to build out the results and store them for display?

Rails - Simple Form - style error messages

I'm trying to make a partial in my views folder, which his shared for error messages.
I want to remove the simple form standard error message and replace it with my own styling - across all models.
My question is, how do I reference the relevant model in my partial. Depending on where its used, it needs to reference the form in which the partial is included.
For example, the standard simple form error block is:
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project_question.errors.count, "error") %> prohibited this question from being
saved:</h2>
<ul>
<% #project_question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
How do I replace #question, with #[whatever the relevant model is called]?
Thank you
For this you can make a partial _error_messages,html.erb
<% if model.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(model.errors.count, "error") %> prohibited
this from being saved:
</h2>
<ul>
<% model.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And you can render this partial in your view as:
<%= render partial: "error_messages", locals: {model: #question} %>
Your answer is a passing a local variable http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
<%= render partial: "your_partial", locals: {question: #question} %>

how to display an item once from a list where that item shows up multiple times in ruby

I've written the code in my .html.erb file but am thinking it might more sense to write it in my controller? This code returns all the names. I'm trying to figure out how to fetch a tag name only once and if a user inputs a tag name that has already been used it does not show up again.
<ul>
<% #pictures.each do |pic| %>
<% pic.tags.each do |tag| %>
<li>
<%= tag.name %>
</li>
<% end %>
<% end %>
</ul>
<ul>
<% #pictures.collect{|x| x.tags.uniq}.flatten.uniq.each do |tag| %>
<li>
<%= tag.name %>
</li>
<% end %>
</ul>
Using Enumerable#flat_map and Array#uniq:
<ul>
<% #pictures.flat_map { |pic| pic.tags.map(&:name) }.uniq.each do |name| %>
<li>
<%= name %>
</li>
<% end %>
</ul>
Example
<ul>
<% #pictures.each do |pic| %>
<% pic.tags.uniq_by(&:name).each do |tag| %>
<li>
<%= tag.name %>
</li>
<% end %>
<% end %>
Use the Array#- method for all items collected that the user enters.
this is relative to how you store the tag values, inside your save method you should make the tags array to be uniq.

Control Structure in Rails Partial

I'm building a Rails app up from the Sample App featured in Michael Hartl's book. In order to display error messages on user signup, I'm using a partial in the shared directory - app/views/shared/_error_messages.html.erb:
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
<% if #data.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(#data.errors.count, "error") %>.
</div>
<ul>
<% #data.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Originally, this partial just started with something like:
<% if #user.errors.any? %>
However, since I've decided to re-use this partial to show errors on other pages, I'm having to use different objects (#user, #fact) depending on which page I'm using it on. This is easily solved by adding that IF statement at the top,
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
-but this feels icky. Is there a controller somewhere I should be putting this kind of logic for shared partials?
You can pass local variables to partial instead:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And in your template, for example:
<%= render 'shared/error_messages', object: #user %>
Marek's answer is probably the best. However, here is an alternative which though not scalable, is closer to what you have done.
Just replace:
<%if #fact %>
<% #data = #fact %>
<% elsif #user %>
<% #data = #user %>
<% end %>
with:
<% #data = #fact||#user %>
You could use render to point to the partial from your controllers for users and fact. Check out the API documentation on rendering partials.

content_for shows only in that view, not others

In my activities view I use a content_for like this:
<% content_for :activities do %>
<div id="contentblock">
<div class="content_title general"></div>
<ul id="updates">
<% #activities.each do |activity| %>
<li><%= activity.created_at.in_time_zone.strftime("%d-%m-%Y # %H:%M") %><br /><%= activity.activity %></li>
<% end %>
</ul>
</div>
<% end %>
And in the application layout I want to show this by doing this:
<% if content_for?(:activities) %>
<%= yield :activities %>
<% end %>
However, it only shows if the activities view is active, not in others views. Why is that?

Resources