undefined local variable Ruby Partial - ruby-on-rails

I'm passing down some variables to a partial. model variable prints out just fine. But I cannot seem to add any other variables. I've tried it a few different ways.
<%= render partial: 'layouts/modals/header', locals: {title: t('layouts.issue'), b: "b", modal: "issue_modal"} %>
Also tried it as
<%= render 'layouts/modals/header', title: t('layouts.issue'), b: "b" , modal: "issue_modal" %>
in header partial
<div class="row mx-0">
<div class="modal-header w-100 row mx-0 justify-content-between p-t">
<button id="create-back" class="btn btn-lg float-left text-rocket-grey-light text-uppercase" data-modal="<%= modal %>" type="button" name="button"><%= t('buttons.cancel') %></button>
<button id="create-submit" class="btn btn-lg float-right btn-danger bg-rocket-red text-rocket-black" data-modal="<%= modal %>" type="button" name="button"><%= t('layouts.create') %></button>
<%= b %>
<%= modal %>
</div>
<div class="modal-title w-100 pl-3">
<div class="text-danger m-t m-l text-uppercase font-weight-bold">
<%= t('layouts.create') %> <%= title %>
</div>
</div>
</div>
no matter what I keep getting undefined local variable or method `b' for #<#<Class:0x00007fa3a43661c8>:0x00007fa3a53a2320> It doesn't make any sense to me that model and title print out fine but "b" is undefined. Ultimately I am trying to pass in a form builder object so I can put form.submit in my _header partial

Related

Is it possible to put a modal inside a card?

I have a modal that's inside a Bootstrap Card for a confirmation if the user really wants to cancel a booking. The problem is that it doesn't show up when clicked. I see the fade effect and that's about it.
<% if Date.current.strftime('%Y-%m-%d') == data.formatted_date_time_for_comparison %>
<%= f.submit 'Cancel Booking', class: "btn btn-danger" %>
<% else %>
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#myModal">Cancel Booking</button>
<div class="modal fade text-dark" id="myModal">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Confirm Cancellation</h3>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
Are you sure you want to cancel this booking?
</div>
<div class="modal-footer">
<%= f.submit 'Cancel Booking', class: "btn btn-danger" %>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<% end %>
It compares the current date to the date of the booking's departure date and it gives a submit button straight to the controller, which in turn rejects it because cancelling on the same date isn't allowed. If that's not the case it gives a button for a modal to activate.
I'm mostly sure it's because of it buried beneath divs, specifically divs with bootstrap card classes.
Here are its parent divs:
<div class="margin-top" style="width: 600px;">
<div class="bg-dark p-3 rounded">
<h3>Reservations</h3>
</div>
<div id="accordion" class="mt-3 mb-4">
<div class="card bg-dark">
<% #reservations.reverse().each do |data| %>
<a class="btn text-light card-header" data-bs-toggle="collapse" href="#id-<%= data.id %>">
<div class="row" style="text-align: left;">
<div class="col">
<strong>Name: </strong><%= data.name %><br><br>
<!-- other records -->
</div>
<div class="col">
<strong>Departure: </strong><%= data.departure %><br>
<!-- other records -->
</div>
</div>
</a>
<div id="id-<%= data.id %>" class="collapse" data-bs-parent="#accordion">
<div class="card-body">
<div class="row">
<div class="col">
<strong>Base Price: </strong><%= data.base_price %><br>
<!-- other records -->
</div>
<div class="col d-flex align-items-end justify-content-end">
<%= form_for #cancellation, url: del_rsrv_path do |f| %>
<%= f.hidden_field :id, value: data.id %>
<%= f.hidden_field :datetime, value: data.formatted_date_time_for_comparison %>
<!-- code posted above here -->
I checked and it does work just below the first div (didn't check on deeper divs), but the problem would be passing the form params there. I'm asking if there's a workaround in either situation.
EDIT: I renamed the data-bs-target name and its respective id name and it somehow works now.

Rails wrongly interpreting http method when adding new nested record

I've got a form with nested attributes fields, made with form_with model:
<%= form_with model: [ :admin, #event ], local: true, class: "event-form" do |form| %>
<%= form.hidden_field :event_category_id %>
<div class="row">
<div class='col-xs-12 col-sm-7'>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
Wersja Polska
</li>
<li role="presentation">Wersja Angielska</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane panel panel-default fade in active" id="<%= dom_id #event %>-pl-tab">
<div class='panel-body'>
<div class='checkbox'>
<label>
<%= form.check_box :pl_active, class: 'panel-activator' %>
Aktywna
</label>
</div>
...
and in that form i'm using fields_for nested attributes:
<div class='panel panel-default'>
<div class='panel-heading'>
<div class='row'>
<div class='col-xs-6'>
<%= form.label :event_variants %>
</div>
<div class='col-xs-6 text-right'>
<%=link_to 'Dodaj', new_admin_event_variant_path( event_id: #event, index: #event.event_variants.size ), id: "add-event-variant", class: 'btn btn-sm btn-primary', remote: true %>
</div>
</div>
</div>
<div class='panel-body event-variants sortable'>
<%- #event.event_variants.each_with_index do |event_variant, index| %>
<%= render partial: 'admin/event_variants/form', locals: { event_variant: event_variant, index: index } %>
<% end %>
</div>
</div>
and a partial looks like:
<div id="event_variant-<%= index %>" class='panel panel-default'>
<%= fields_for "event[event_variants_attributes][]", event_variant, child_index: index do |fields| %>
<%= fields.hidden_field :id %>
<%= fields.hidden_field :position %>
<%= fields.hidden_field :_destroy %>
<div class='panel-heading'>
<div class='row'>
<div class='col-xs-6 variant-title'>
<%= event_variant.pl_title || 'Nowy element' %>
</div>
<div class='col-xs-6 text-right'>
<label class='btn btn-sm btn-primary'>
<%= event_variant.image&.file.present? ? 'Zmień zdjęcie' : 'Dodaj zdjęcie' %>
<%= fields.file_field :image, style: 'display:none', class: 'add-image' %>
</label>
<div class='btn btn-sm btn-danger remove-variant'>Usuń</div>
</div>
</div>
</div>
<div class='image-container' style="background-image:url('<%= event_variant.image&.file.present? ? event_variant.image.url : image_path('no-image-icon') %>')" >
</div>
<div class='panel-body'>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
Wersja Polska
</li>
<li role="presentation">Wersja Angielska</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane panel panel-default fade in active" id="event_variant-<%= index %>-pl-tab">
<div class='panel-body'>
<div class='checkbox'>
<label>
<%= fields.check_box :pl_active, class: 'panel-activator' %>
Aktywna
</label>
</div>
<div class="form-group">
<%= fields.label :pl_title %>
<%= fields.text_field :pl_title, class: 'form-control', disabled: !event_variant.pl_active %>
</div>
<div class="form-group">
<%= fields.label :pl_description %>
<%= fields.text_field :pl_description, class: 'form-control', disabled: !event_variant.pl_active %>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane panel panel-default fade" id="event_variant-<%= index %>-en-tab">
<div class='panel-body'>
<div class='checkbox'>
<label>
<%= fields.check_box :en_active, class: 'panel-activator' %>
Aktywna
</label>
</div>
<div class="form-group">
<%= fields.label :en_title %>
<%= fields.text_field :en_title, class: 'form-control', disabled: !event_variant.en_active %>
</div>
<div class="form-group">
<%= fields.label :en_subtitle %>
<%= fields.text_field :en_description, class: 'form-control', disabled: !event_variant.en_active %>
</div>
</div>
</div>
</div>
</div>
<% end %>
</div>
thats attributes are has_many related with main model, so beside fields to edit each of nested model, I can click to render new fields_for partial to create nem nested record - common thing I guess:
<%=link_to 'Dodaj', new_admin_event_variant_path( event_id: #event, index: #event.event_variants.size ), id: "add-event-variant", class: 'btn btn-sm btn-primary', remote: true %>
going to:
def new
#event = Event.find params[:event_id]
#event_variant = #event.event_variants.build( pl_active: false, en_active: false )
#index = params[:index]
end
and rendering js.erb:
$('.event-variants').append("<%= j render( partial: 'form', locals: { event_variant: #event_variant, index: #index } ) %>")
the problem starts when i'm trying to edit main record. When I'm only changing values of fields, adding images, etc. no matter if in main or nested fields its working ok, sending PATCH, updating record and nested ones.
BUT:
when I'm trying to add new nested record, by those fields rendered via js.erb, form is send with POST instead of PATCH to route: /events/:id and of course its generating RoutingError:
Invalid or incomplete POST params
Started POST "/admin/events/14" for 127.0.0.1 at 2019-09-16 11:19:11 +0200
ActionController::RoutingError (No route matches [POST] "/admin/events/14"):
form attributes are not changing. HTML still looks like:
<div class="panel-body">
<form class="event-form" enctype="multipart/form-data" action="/admin/events/14" accept-charset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓">
<input type="hidden" name="_method" value="patch">
<input type="hidden" name="authenticity_token" value="Z3Uhd6EgZ+N16P5MKbqLDs3F1d94iEokD4O5q63V04q/ofFblB5sRCmEO2m+coHayDrQ/zDNVHSzfSzmDGrxog==">
<input type="hidden" value="2" name="event[event_category_id]">
<div class="row">
<div class="col-xs-12 col-sm-7">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
Wersja Polska
</li>
<li role="presentation">Wersja Angielska</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane panel panel-default fade in active" id="event_14-pl-tab">
<div class="panel-body">
<div class="checkbox">
<label>
<input name="event[pl_active]" type="hidden" value="0">
<input class="panel-activator" type="checkbox" value="1" checked="checked" name="event[pl_active]">
Aktywna
</label>
...
even with _method field set to PATCH
even if I manualy set a method in form_with by method: #event.persisted? ? :patch : :post
Everything works correctly when no new nested record.
And last but not least, I'm not changing anything via js onSubmit nor onClick when submitting.
Any ideas what could went wrong here?
I got this problem when a form field wasn't valid.
name="blah[]" # this isn't valid
See ActionController::BadRequest (Invalid request parameters: expected Array (got Rack::QueryParser::Params) on ajax post
Putting a pry in this file helped me out
/2.7.4/lib/ruby/gems/2.7.0/gems/rack-2.2.3.1/lib/rack/method_override.rb
def method_override_param(req)
binding.pry
req.POST[METHOD_OVERRIDE_PARAM_KEY]

Rails 4 - dynamically populate bootstrap tabs

I am trying to make a set of tab content fields in my Rails 4 app.
I have a problem because I want the first tab to be displayed (and then the others display as you click through them).
I have 6 tab placeholders, which might be used, depending on whether an attribute is marked as true or false. If one attribute is false, then there is one fewer tab.
If the content that is lined up in the first tab belongs to the attribute which is false, I can't figure out how to make the first tab display (without needing to first click on it).
For example, the first to tabs are below:
<div class="dp-tab-1">
<ul class="dp-tab-list row" id="myTab">
<% if #project.package.has_background_ip == true %>
<li class="col-md-2 col-xs-6 active" >
<a href="#tab-content-first">
<span class="glyph-item" data-icon=""></span>
<span>BACKGROUND INTELLECTUAL PROPERTY</span>
</a>
</li>
<% end %>
<li class="col-md-2 col-xs-6">
<a href="#tab-content-second">
<div class="glyph-item" data-icon=""></div>
<span>DATA</span>
</a>
</li>
The content for those two tabs is:
<div class="dp-tab-content tab-content">
<div class="tab-pane row fade in active" id="tab-content-first">
<% if #project.package.has_background_ip == true %>
<div class="col-md-6 text-center">
<%= image_tag(#project.package.background_ip.bip_image, :class=>"wow fadeInLeft img-responsive", :alt=>"123") %>
</div>
<div class="col-md-6">
<div class="tab-inner">
<h4>EXISTING INTELLECTUAL PROPERTY</h4>
<p class='medium-text'>
<%= render 'projects/bipparticulars' %>
</p>
<br/>
<a class='btn btn-danger btn-line'>CHECK THESE IP TERMS</a>
</div>
</div>
<% end %>
</div>
<div class="tab-pane row fade" id="tab-content-second">
<div class="col-md-6">
<div class="tab-inner">
<h4>DATA</h4>
<p class='medium-text'>
<%= render 'projects/dataparticulars' %>
</p>
<br/>
<% if #project.package.datum.survey_link == true %>
<a class='btn btn-danger btn-line'>SURVEY</a>
<% end %>
<% if #project.package.datum.confidential == true %>
<a class='btn btn-danger btn-line'>PROPOSED NDA</a>
<% end %>
</div>
</div>
<div class="col-md-6">
<%= image_tag(#project.package.background_ip.bip_image, :class=>"wow fadeInUp img-responsive", :alt=>"123") %>
</div>
</div>
The first tab has:
<% if #project.package.has_background_ip == true %>
If that attribute is true, then the tab displays and everything works fine.
If that attribute is not true, then the tab does not display and everything else works fine, EXCEPT that the second tab does not show its content automatically - i first have to click on the tab to reveal its content.
I want the first true tab to have its contents on display.
How can I achieve that?
You should set active class for the second tab to be selected automatically in order to show content :
<div class="dp-tab-content tab-content">
<div class="tab-pane row fade in <%= project.package.has_background_ip == true ? 'active' : '' %>" id="tab-content-first">
<% if #project.package.has_background_ip == true %>
<div class="col-md-6 text-center">
<%= image_tag(#project.package.background_ip.bip_image, :class=>"wow fadeInLeft img-responsive", :alt=>"123") %>
</div>
<div class="col-md-6">
<div class="tab-inner">
<h4>EXISTING INTELLECTUAL PROPERTY</h4>
<p class='medium-text'>
<%= render 'projects/bipparticulars' %>
</p>
<br/>
<a class='btn btn-danger btn-line'>CHECK THESE IP TERMS</a>
</div>
</div>
<% end %>
</div>
<div class="tab-pane row fade <%= project.package.has_background_ip == false ? 'active' : '' %>" id="tab-content-second">
<div class="col-md-6">
<div class="tab-inner">
<h4>DATA</h4>
<p class='medium-text'>
<%= render 'projects/dataparticulars' %>
</p>
<br/>
<% if #project.package.datum.survey_link == true %>
<a class='btn btn-danger btn-line'>SURVEY</a>
<% end %>
<% if #project.package.datum.confidential == true %>
<a class='btn btn-danger btn-line'>PROPOSED NDA</a>
<% end %>
</div>
</div>
<div class="col-md-6">
<%= image_tag(#project.package.background_ip.bip_image, :class=>"wow fadeInUp img-responsive", :alt=>"123") %>
</div>
</div>
Hopefully! It will help.

Rails: Render partial content if parameter is present

I'm trying to conditionally render a section of a partial, if the render includes a particular parameter "has_footer".
In _modal.html.erb, I have the following:
<div id="<%= id %>" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-header">
<button type="button" class="btn-modal-close" data-dismiss="modal" aria-hidden="true">×</button>
<header><%= title %></header>
</div>
<div class="modal-body">
<%= render partial: content %>
</div>
<% if params[:has_footer] %>
<div class="modal-footer">
<button class="btn-modal-save">Save</button>
<button class="btn-modal-cancel" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
<% end %>
</div>
And I render the partial like this:
<%= render "pages/modal", :has_footer, id: "modal-add-campaign", title: "Add Campaign", content: "pages/modal_add_campaign" %>
Basically, I want to display the div "modal-footer" only if I include the ":has_footer" parameter in my render command.
Any help, please?
Variables passed to partials are treated like local variables. So i would do something like:
<%= render :partial => "pages/modal", locals: { has_footer: true, id: "modal-add-campaign", title: "Add Campaign", content: "pages/modal_add_campaign" } %>
And check the variable like this:
if has_footer

how to not improve this code to not repeat the twitter bootstrap modal?

I have a Project that have many Pictures. I am using the first picture as a link to call a twitter bootstrap modal, where some information will be displayed as well as the link for the project`s page.
<!-- Modal -->
<div id="<%= project.id %>" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3><%= project.title %> <small><%= project.sub_title %></small></h3>
</div>
<div class="modal-body">
<p><%= ActionView::Base.full_sanitizer.sanitize (project.description) %></p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= link_to 'More Details', project_path(project), class: 'btn btn-primary' %>
</div>
</div>
In order to get the modal working for each project, I have added the project.id to the Modal id. So, I am actually creating many modals, one for each project.
<% #projects.each do |project| %>
<%= link_to (image_tag project.pictures.first.url), "##{project.id}", class: 'btn', role: 'button', data: { toggle: 'modal' } %>
<%= render 'projects/modal', project: project %>
<% end %>
Well, everything is working fine, but I don't like it! It will became a loading problem if I have many projects.
So, I would like to find a way to not load all modals. I would like to have one modal template that is populated by the project information.
Any idea on how to improve it?
NOTE: I don't have rails set up at the moment, so can't test this directly, but should work:
Put the following generic modal code into the modal partial:
<div id="genericModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3></h3>
</div>
<div class="modal-body">
<p></p>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<%= link_to 'More Details', nil, class: 'btn btn-primary' %>
</div>
</div>
Include the following at the top of your view:
<script>
function populateModal(projectId) {
$(".modal-header").find("h3").html($(projectId).find("#p_title").html());
$(".modal-body").find("p").html($(projectId).find("#p_desc").html());
$(".modal-footer").find("a").attr("href", $(projectId).find("#p_link > a").attr("href"));
$("#genericModal").modal('show');
}
</script>
Then further down in your view, you can do something like this:
<%= render 'projects/modal' %>
<% #projects.each do |project| %>
<%= link_to (image_tag project.pictures.first.url), html => {:onclick => "populateModal('##{project.id}')", :class => 'btn', :role => 'button'} %>
<div id="#{project.id}" class="hide">
<span id="p_title"><%= project.title %> <small><%= project.sub_title %><small></span>
<span id="p_desc"><%= ActionView::Base.full_sanitizer.sanitize (project.description) %></span>
<span id="p_link"><%= link_to project_path(project) %></span>
</div>
<% end %>
Create a single modal, not one for each project. Use javascript to open the modal on each link (instead of data-toggle="modal") and before you do, set the project's title, subtitle, description and link using Javascript.

Resources