Rails Locals - Passing Connected Model Data - ruby-on-rails

My model structure is pretty solid. I have MarketingDeliverySystem has_many MarketingSections. MarketingSections has_many MarketingVideos.
I have another segment: GroupDevelopment has_many GroupSections. GroupSections has_many GroupVideos.
I'm trying to use a partial to pass the variables, thus DRYing it all up.
I have the following that I'm trying to pass to the partial:
= render partial: '/sales_presentations/sales_presentation',
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system}
Then in the partial I have the following:
.rounded-box-header.blue-bg #{sales_presentation.title}
ul
- sales_presentation.sections.ordered.each_with_index do |section, index|
- list_class = 'section show'
- list_class = 'section hide' if index != 0
li
= link_to section.title, '#', class: 'section', data: { id: section.id }
ul class="#{list_class}" data-section-id="#{section.id}"
- section.videos.ordered.each do |video|
li.video
= link_to video.title, '#',
class: 'video video-link',
data: { video: video.youtube_link,
sales_presentation: sales_presentation.title.parameterize }
.seven.columns
.row
div id="#{sales_presentation.title.parameterize}-container"
video {
id="#{sales_presentation.title.parameterize}-video-player"
class="video-js vjs-default-skin videos"
height=400
poster=""
controls preload='none'
data-default-url="#{first_video(sales_presentation)&.youtube_link}"
I previously had issues with sales_presentation.title at the top until I updated the locals.
My question/issue is how do I pass in through the locals to use for sales_presentation.sections instead to use #marketing_delivery_system.marketing.sections?
I thought I could just put that in through locals:
sales_presentation.sections: #marketing_delivery_system.marketing_sections but I end up with a massive syntax error.
I've also tried creating a partial view for these two and then changed sales_presentation throughout the view to mod. Then changed mod.sections to mod_section and setting that in the locals to mod_section: #marketing_delivery_system.marketing_section. The problem then gets into that I end up needing to hit video later in the iteration. So then that has the same issue.

You misunderstand the meaning of locals in partials.
Says we have
<%= render partial: 'image', locals: {size: #image.size, extension: #image.extension} %>
It means that in image partial now we can use local variable size and extension (keys) as #image.size and #image.extension (values).
Put in locals: {} all local variables you want.
So you can't write in locals sales_presentation.sections: #marketing_delivery_system.marketing.sections
But you can sales_presentation_sections: #marketing_delivery_system.marketing.section
Also you have problem with this code:
locals: { marketing_delivery_system: #marketing_delivery_system,
first_video: first_marketing_video(#marketing_delivery_system),
sales_presentation: #marketing_delivery_system }
marketing_delivery_system and sales_presentation will be with the same value.

Related

Is there a way to pass a local that is item dependent when rendering a collection rails 6

I have below line as the last statement in my controller action:
render json: {
html: render_to_string(
partial: "_item_content.html.haml",
collection: items, as: :item,
locals: {
seller: #seller
}, layout: false),
is_last_page: items.last_page?
}
In my partial I am doing item_discount = item.eligible_discount_for(current_user) which is what I want to avoid.
Is there a way to compute and pass eligible_discount as a local for each item while rendering the partial in the controller action? If not, how can I refactor this so I don't have to do the item_discount = item.eligible_discount(current_user) computation in the partial.
As I had to finish this quickly, below is what I did to keep the partial a bit cleaner and do the computation in the action, though I am not really sure it's the best way. Basically, instead of passing the collection to render, changed it to loop over the collection and aggregate the individual strings. Posting in case anyone else finds this useful, or can provide feedback to improve.
items_html = items.map do |item|
eligible_discount = item.eligible_discount_for(current_user)
render_to_string(partial: "item_content.html.haml",
locals: {
item: item,
seller: #seller,
eligible_discount: eligible_discount
},
layout: false)
end.reduce("", :+)
render json: {
html: items_html,
is_last_page: items.last_page?
}

Render partials inside loop in Rails 5

Question: How do I make a partial (that has to be generic) loop through different variables?
I have a tabbed page where I want to use a partial to avoid duplicating my HTML. The tabs are "Videos" and "Articles". It's the exact same HTML but I want to iterate through #videos for videos and #articles for articles.
The idea was to make the product partial completely generic and then somehow pass in #videos or #articles that I want to iterate through.
Partial: _product.html.slim
.col-md-5
.thumbnail
.thumb.spacer-sm
- if product.image.blank?
iframe allowfullscreen="" frameborder="0" mozallowfullscreen="" src="https://player.vimeo.com/product/#{product.vimeo_id}" webkitallowfullscreen=""
- elsif product.vimeo_id.blank?
= image_tag(product.image.url,
class: 'img img-responsive img-rounded')
.caption
.content-group-sm.media
.media-body
h6.text-semibold.no-margin
= product.name
small.text-muted
| by
= product.user.name
- unless product.price.blank?
h6.text-success.media-right.no-margin-bottom.text-semibold
| $
= product.price
= product.description
.panel-footer.panel-footer-transparent
.heading-elements
ul.list-inline.list-inline-separate.heading-text
li
= link_to 'Delete', product_path(product), method: :delete
li
= link_to 'Edit', edit_product_path(product)
HTML view rendering the partial:
.page-container.spacer-minus
.page-content
.row
.col-md-4
.sidebar-default.sidebar-separate
.sidebar-content
.content-group
.panel.no-border-radius-top
ul.navigation
li.navigation-header Navigation
li.active
a data-toggle="tab" href="#videos"
i.icon-video-camera2
| Videos
li
a data-toggle="tab" href="#articles"
i.icon-graduation
| Articles
.col-md-8
.tab-content
#videos.tab-pane.fade.in.active
.row
- #videos.each do |product|
= render 'shared/product'
#articles.tab-pane.fade
.row
- #articles.each do |product|
= render 'shared/product'
I just need my loop to understand what variable I want to iterate through. I cannot include #video or #article in the partial since that will defeat the purpose of having a generic partial.
With this implementation, I get the error:
undefined local variable or method `product' for #<#<Class:0x007fc58053ae60>:0x007fc58884ea68>
Try this code:
#videos.tab-pane.fade.in.active .row -
#videos.each do |video|
= render 'shared/product', product: video
#articles.tab-pane.fade .row -
#articles.each do |article|
= render 'shared/product', product: article
Hi this is pretty stuff if you want articles to come after the videos then try this.
= render partial: "product", collection: #videos
= render partial: "product", collection: #articles
this will remove the loop from your main view but in your case you are not using locals try this
.row
- #videos.each do |video|
= render 'shared/product', locals: {product: video}
.row
- #articles.each do |article|
= render 'shared/product' , locals: {product: article}
It will work.

Rails - Know caller filename when using render layout

I want to dynamically add classes to a container based on the name of the class that called my layout using the render method. Is it possible or do I need to pass it manually from each view?
File: emails/inbox.html.haml
render layout: 'shared/v3/panel' do
// whatever
Rendered HTML:
<div id="inbox" class="panel email_container"></div>
My temp solution is to do:
render layout: 'shared/v3/panel', locals: {class_panel: 'email_container', id_panel: 'inbox'} do
// whatever
But I want to do that dynamically.
Final solution: views/shared/_panel.html.haml
- # You need to use: "render layout", not "render partial" to pass the "do" block.
.container_content{class: "#{controller_name}_container #{local_assigns[:panel_class] ? panel_class : ''}", id: action_name}
- if local_assigns[:title]
.headline= local_assigns[:title]
= yield
- if local_assigns[:footer]
.footer= local_assigns[:footer]
- # Example of use:
-#= render layout: 'shared/v3/panel', locals: {title: 'Place', panel_class: 'my_custom_class'} do
-# - if #activity.place.present?
-# %p
-# = t('place')
-# = #activity.place

Stagger the rendering of multiple partials using Rails

I've got the following situation:
1. Using a javascript function to begin an AJAX call
$(".toggle").click(function() {
var currentId = $(this).attr('id');
$(this).find(".loadingDiv").show();
$(this).find(".matchingsDiv").load("<%= matches_companies_url %>?id=" + currentId, null, function(){
$('.loadingDiv').hide();
});
return false;
});
2. Rendering matches.js.erb
<% #matchings.each_with_index do |match, index| %>
<%= (render :partial => 'companies/matching', :locals => {:match => match, :project => #project}) %>
<% end %>
The above code works. Here's a little question: how can I stagger the rendering of each matching?
i.e. Can I make the first matching render immediately, the next matching after 200ms, the third after 400ms, and so on?

Partial not receiving all variables from :locals

In my controller I have:
- #items.each do |item|
= render :partial => 'item', :locals => { :item => item, :draggable => true }
And in the item partial I have:
%span{:id => "item_#{item.id}", :class => 'item'}
= item.name
- if defined?(draggable)
= draggable_element "item_#{item.id}", :revert => true
This is not working, however, because defined?(draggable) returns false. The draggable_element is never rendered.
I know that item is passed through :locals because the rest of the partial renders. If I change the partial to read:
- if defined?(item)
= draggable_element "item_#{item.id}", :revert => true
Then the draggable_element is rendered.
Any idea why :draggable is not getting passed to the partial?
Use local_assigns[:draggable] instead of defined?(draggable).
From the Rails API "Testing using defined? var will not work. This is an implementation restriction."
I've solved this problem in the past by throwing this into the top of the partial.
<% draggable ||= nil %>
That allows me to do
<% if draggable %>
So long as I don't try to make the distinction between draggable being nil and never being passed.

Resources