I can only edit my first post - ruby-on-rails

I'm currently facing a strange problem. I'm trying to implement the basics actions into an ajax window. And my problem is that when I'm trying to edit a ranch(like a post), it's always rendering the edit of my first ranch.
This is my code :
(ranch controller)
before_action :set_ranch, only: [:show, :edit, :update, :destroy]
def index
#ranches = current_user.ranches
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ranch
#ranch = Ranch.find(params[:id])
end
(ranch/index)
<%- #ranches.each do |ranch| %>
<div class="box panel panel-default">
<h2><%=link_to ranch.name, ranch%></h2>
<div class="image_wrapper">
<%= link_to (image_tag "ranch.jpg"), ranch %>
</div>
<button type='button' class='btn btn-default' data-toggle='modal' data-target='#MyEditRanch' aria-hidden="true" remote="true" style="float:right; margin-top: 10px;">
<i class="fa fa-cog"></i>
</button>
</div>
<!-- modal Edit -->
<div id='MyEditRanch' class='modal fade' role='dialog' aria-hidden="true">
<div class="modal-dialog">
<div class='content'>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Edit <%=ranch.name%></h3>
</div>
<div class="modal-body">
<%= render 'form2', ranch: ranch%>
</div>
</div>
</div>
</div>
<!-- /modal Edit -->
<%end%>
( & my _form2)
<%= simple_form_for(ranch) do |f| %>
<%= f.error_notification %>
<% if ranch.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(ranch.errors.count, "error") %> prohibited this ranch from being saved:</h2>
<ul>
<% ranch.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="col-lg-6">
<div class="input-group" style=" margin-left: 70px;">
<div class="input" style="width: 400px; margin-top: -10px; text-align: center;" >
<%= f.input :name, label: false, style:"margin:0px;", placeholder: "Name of your ranch"%>
</div><!-- /btn-group -->
</div><!-- /input-group -->
<div class="form-actions" style="max-width: 300px">
<%= f.button :submit, style:"text-align:center; margin-left: 70px;" %>
</div>
<%= link_to "Delete", ranch_path(ranch), method: :delete, data: {confirm: "Are you sure that you want to delete this ranch ?"}, class: "btn btn-danger", style:"margin-left: 140px;" %>
<% end %>
</div>
So if you have any advice to solve this shit, you're welcome !!
Thanks in advance

In HTML, ids must be unique on the page.
ie there must be only one of them...
This means there must be only one div that has the id MyEditRanch...
Sometimes the browser lets you get away with it... but if you have JS that uses that id (eg to toggle a modal)... it will still go looking for the first instance of that id on the page to toggle... ie onlyt he first one.
If you want to display multiple ranches - each with their own edit modal... then you really must give each one its own unique id to toggle.
eg append the ranch's id to it in both the button and the edit-modal. eg
<button type='button' data-toggle='modal' data-target='#edit-ranch-<%= ranch.id %>' ...
<!-- and later -->
<div id='#edit-ranch-<%= ranch.id %>'

Related

Rails stimulus one form change for many urls and turbo frames

I am building a dashboard with multiple elements like charts, tables, simple fields with calculated values etc and I want to use Rails7 with stimulus.
In the past I used jQuery so I just created empty elements and then called several ajax requests in paralel to get data for every elements and populate it. So initial page load was super fast and then it loaded all necessary data. Dashboard had few dropdowns options to change data and when I loaded page I just sent defaults. Every dropdown change reloaded all data for all elements by filter used in dropdown.
How to do similar approach with stimulus?
When I use turbo form what I can do is submit form on page load, but it looks ugly (page initially loads and instantly reloads). And if I have many elements it gets slow because it first needs to finish all calculations.
this is my simple filter with 2 dropdowns
<%= form_with url: "", method: :get, data: { controller: "home", home_target: "form", turbo_frame: "home_dashboard", turbo_action: "advance" } do |form| %>
<div class="row">
<div class="d-sm-flex align-items-center mb-3">
<div class="col-lg-2" >
<%= form.select :city, options_for_select(City.all.pluck(:name,:id)), {include_blank: (t 'all')}, {class: 'form-select', data: {action: "input->home#search"}} %>
</div>
<div class="col-lg-2" >
<%= form.select :year, options_for_select(#years.reverse, (params[:year] || Date.today.year)), {selected: params[:year], include_blank:false}, {class: 'form-select', data: {action: "input->home#search"}} %>
</div>
</div>
</div>
<% end %>
and this is my home controller in stimulus which is simple
import { Controller } from "#hotwired/stimulus"
// Connects to data-controller="home"
export default class extends Controller {
connect() {
}
static targets = ["form"]
connect() {
this.formTarget.requestSubmit()
}
search() {
this.formTarget.requestSubmit()
}
}
my rails controller gets ugly big because I am calculating lot of fields dynamically and showing them in turbo frame tag...this is just a part of data I want to show so there should be much more
<%= turbo_frame_tag "home_dashboard" do %>
<div class="row">
<div class="col-xl-6">
<div class="card border-0 mb-3 overflow-hidden ">
<div class="card-body">
<div class="row">
<div class="col-xl-7 col-lg-8">
<div class="mb-3 fs-13px">
<b><%= (t 'invoices.invoiced').upcase %></b>
</div>
<div class="d-flex mb-1">
<% if #invoices_sumed.present? %>
<h2 class="mb-0"><span data-animation="number" data-value="<%= #invoices_sumed[0][1] %>"><%= #invoices_sumed[0][1] %></span> <%= #invoices_sumed[0][0] %></h2>
<% else %>
<h2 class="mb-0"><span data-animation="number" data-value="0">0</span> EUR</h2>
<% end %>
</div>
<div class="mb-3">
<i class="fa fa-caret-up"></i> <span data-animation="number" data-value="<%= #invoices_sumed_compare %>"><%= #invoices_sumed_compare %></span>% <%= t 'invoices.compared_previous_year' %>
</div>
<hr>
<div class="row text-truncate">
<div class="col-6">
<div class=""><%= t 'invoices.total' %></div>
<div class="fs-18px mb-5px fw-bold" data-animation="number" data-value="<%= #invoices.size %>"><%= #invoices.size %></div>
<div class="progress h-5px rounded-3 mb-5px">
<div class="progress-bar progress-bar-striped rounded-right " data-animation="width" data-value="<%= calc_year_ratio(#invoices.size,#invoices_total_size) %>%" style="width: <%= calc_year_ratio(#invoices.size,#invoices_total_size) %>%;"></div>
</div>
</div>
<div class="col-6">
<div class=""><%= t 'invoices.average' %> <small>(<%= (t 'invoices.median').to_s + ":" %> <strong><%= "#{#invoices_median_value.round(2)} #{#invoices_top_currency}" %></strong>)</small></div>
<div class="fs-18px mb-5px fw-bold"><span data-animation="number" data-value="<%= #invoices_avg_value.round(2) %>"><%= #invoices_avg_value.round(2) %></span> <%= #invoices_top_currency %></div>
<div class="progress h-5px rounded-3 mb-5px">
<div class="progress-bar progress-bar-striped rounded-right bg-orange" data-animation="width" data-value="<%= calc_median_total_ratio(#invoices_avg_value,#invoices_max_value) %>%" style="width: <%= calc_median_total_ratio(#invoices_avg_value,#invoices_max_value) %>%;"></div>
</div>
</div>
</div>
</div>
<div class="col-xl-5 col-lg-4 align-items-center d-flex justify-content-center">
<canvas
data-controller="chart"
data-chart-data-value='<%= #chart_total.to_json %>'
data-chart-options-value="<%= #chart_options.to_json %>"
></canvas>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4">
<div class="table-responsive">
<table id="contractors" class="table table-hover align-middle" style="width:100%;">
<thead></thead>
<tbody>
<% #contractors.each do |contractor| %>
<tr>
<td><%= contractor[0]%></td>
<td><%= contractor[2]%></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
<% end %>
is there any way how to split this in multiple turbo frames with multiple urls to call with one form select change?

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.

RSpec + Capybara scoping returns unexpected results

I have two tables: Suggestions and Keywords.
I'm trying to test removal of items from Keywords (which puts it into Suggestions automatically).
Here's my test:
it "removes a chosen keyword" do
page.first(:link, "Add").click
within(:css, "#keywords") do
find('li:nth-child(1)').click_link('X')
expect(page).to have_no_content(item.search.term)
end
end
It results in:
1) New collection Suggestions removes a chosen keyword
Failure/Error: expect(page).to have_no_content(item.search.term)
expected not to find text "Gift for her" in "Keywords\nGift for her X"
# ./spec/features/collections_spec.rb:60:in `block (4 levels) in <top (required)>'
# ./spec/features/collections_spec.rb:53:in `block (3 levels) in <top (required)>'
Here's the print of the body element:
<div class="col-lg-5 col-md-6 mb-4" id="suggestions">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title">Suggestions</h4>
<p class="card-text">
<ul class="list-group list-group-flush" id="suggestion-list">
<li class="list-group-item">
Gift for her
<a class="btn btn-primary" rel="nofollow" data-method="post" href="/collections/1/item/choose.1">Add</a><a class="btn btn-primary" rel="nofollow" data-method="post" href="/collections/1/item/destroy.1">X</a><br>
</li>
</ul>
</p>
</div>
</div>
</div>
<div class="col-lg-5 col-md-6 mb-4" id="keywords">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title">Keywords</h4>
<p class="card-text">
<ul class="list-group list-group-flush" id="keyword-list">
</ul>
</p>
</div>
</div>
</div>
And my show.html.erb file:
<div class="col-lg-5 col-md-6 mb-4" id="suggestions">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title">Suggestions</h4>
<p class="card-text">
<ul class="list-group list-group-flush" id="suggestion-list">
<% if #suggestions %>
<% #suggestions.each do |s| %>
<li class="list-group-item">
<%= Hpricot.uxs s.search.term %>
<%= link_to 'Add', collection_item_choose_path(#collection, s),{ method: :post, class: "btn btn-primary" } %><%= link_to 'X', collection_item_destroy_path(#collection, s),{ method: :post, class: "btn btn-primary" } %><br>
</li>
<% end %>
<% end %>
</ul>
</p>
</div>
</div>
</div>
<div class="col-lg-5 col-md-6 mb-4" id="keywords">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title">Keywords</h4>
<p class="card-text">
<ul class="list-group list-group-flush" id="keyword-list">
<% if #keywords %>
<% #keywords.each do |s| %>
<li class="list-group-item">
<%= Hpricot.uxs s.search.term %>
<%= link_to 'X', collection_item_remove_path(#collection, s),{ method: :post, class: "btn btn-primary" } %><br>
</li>
<% end %>
<% end %>
</ul>
</p>
</div>
</div>
</div>
Seems to me like the scoping is off somehow, although I checked and the link does actually click (you can see it in the puts page.body). Any ideas?
Thanks in advance!
This is unlikely to be a scoping issue since the reported text is "Keywords\nGift for her X" - whereas if it were seeing the text in the "suggestions" section if would have "Add" text in there too.
More likely is the clicking on the 'X' just isn't getting processed by your app due to an error somewhere. Check your test.log to see exactly what methods are being called, and whether there are errors.
Additionally you don't mention what driver you're using with Capybara. If you're using a JS capable driver it's possible you don't have Capybara.default_max_wait_time set high enough for the hardware you're testing on and/or turbolinks (assuming you have that in your app) is getting involved. Again, looking at your test.log should give a better idea of what's actually happening. Another to try would be to use save_and_open_screenshot to get an image of what the actual page looks like (assuming you're using a driver that supports it)
If you're not using a JS capable driver (ie you're using rack_test) then it's possible you haven't required capybara/rails and the method of the links isn't being used. Again, checking test.log will show the method (get vs post) being used for each request.

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.

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