Rails: Different modal for each link - ruby-on-rails

I have this structure in my view:
<ul>
<% #categories.each do |category| %>
<li> <%= category.name %> <a href='#'>Edit</a> </li>
<% end %>
</ul>
Now, I want to popup a modal when I click "Edit" and in this modal to place a form for editing corresponding category. I want to avoid to generate a modal for each element from loop and I want to have a generic modal and call it each time, with specific parameters. Is this possible?

Use remote true for js response
<ul>
<% #categories.each do |category| %>
<li> <%= category.name %><%= link_to 'Edit', edit_category_path(category), remote: true %> </li>
<% end %>
</ul>
<div class='modal-fade' id="edit-modal"></div>
create one partial page _edit.html.erb
write bootstarp modal structure and edit form and in form write remote: true
eg. <%= form_for #category, remote: true do %>......<%end%>
create edit.js file and write as below
$('#edit-modal').html("<%= j render 'edit' %>");
$('#edit-modal').modal('show');
and create one more file create.js
$('#edit-modal').modal('hide');

just create a remote link:
link_to "edit", edit_category_path(category), class: "btn btn-mini", remote: true
Then in your views, add a edit.js.erb file:
$("#myModal").html("<%= j render "new"%>");
$('#myModal').modal('show');
and change your edit.html and new.html files to _new.html and edit.html

Related

Ajax not working inside iteration

I have a AtpRank model containing the first 100 Atp tennis players.
My goal is to create in the view a table listing all tennis players and their attributes, along with a button for each player useful for the user to choose a list of tennis players. The home.html.erb code is below:
<% #atp_ranks.each do |tennis_player| %>
<tr id="tennist-<%= tennis_player.ranking %>">
<td class="atpranking"> <%= tennis_player.ranking %> </td>
<td class="atpname"> <%= tennis_player.name %> </td>
<td class="atppoints"> <%= tennis_player.points %> </td>
<% unless Time.now.month == 12 %>
<td>
<div id="atpenlist_form">
<% if current_user.atpenlisted?(tennis_player) %>
<%= form_for(current_user.atp_selections.find_by(atp_rank_id: tennis_player.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Dump", class: "btn btn-warning btn-sm" %>
<% end %>
<% else %>
<%= form_for(current_user.atp_selections.build, remote: true) do |f| %>
<div><%= hidden_field_tag :atp_id, tennis_player.id %></div>
<%= f.submit "Choose", class: "btn btn-primary btn-sm" %>
<% end %>
<% end %>
</div>
</td>
<% end %>
</tr>
<% end %>
As you can see, the form uses Ajax having set remote: true in the form_for helper.
Requests are handled by the atp_selections controller. Below is an extract of the create action of this controller:
current_user.atpenlist(tennist)
respond_to do |format|
format.html { redirect_to root_url }
format.js
end
The destroy action uses the atpdiscard method instead of the atpenlist method.
In app/views/atp_selections I created the create.js.erb and destroy.js.erb files.
Below is the app/views/atp_selections/create.js.erb file:
$("#atpenlist_form").html("<%= escape_javascript(render('users/atpdiscard')) %>");
$("#atp_count").html('<%= current_user.atp_ranks.count %>');
Each of the app/view/users/_atpenlist.html.erb and app/view/users/_atpdiscard.html.erb partials contain the respective form (the same exact part of the code above starting with form_for).
I have to say that in the original code for the home page I did not explicitly included the entire code for the forms, but I just rendered the partials. This did not work: rails warned me that it could not find the variable or method tennis_player used in the iteration, for some reason to me unknown. So I had to renounce to render the partials and decided to include the entire code.
The issue is now that Ajax does not work: I have to refresh the page to see the results of submitting the form. I checked my code and could not find errors or explanation for this.
tennis_player is a local variable for you home.html.erb .
So you need to pass it in js.erb like
$("#atpenlist_form").html("<%= escape_javascript(render('users/atpdiscard'), locals: {tennis_player: your_tennis_player_object}) %>");
Set the tennis player object in your controller & use that in above js.erb

Rails render partial with block and collection

This is similar to this question but with a collection:
<div class="panel-body">
<%= render layout: 'today_items_list', locals: {items: #pos} do |po| %>
<% #output_buffer = ActionView::OutputBuffer.new %>
<%= link_to "##{po.id}", po %>
<%= po.supplier.name %>
<% end %>
</div>
with partial/layout:
.tableless_cell.no_padding
%h3.no_margin_vertical= title
%ul.no_margin_vertical
- for item in items
%li= yield(item)
This renders as you expect but if I omit the weird '#output_buffer = ActionView::OutputBuffer.new', the buffer is not cleared and the list is rendered this way:
<li>
#4833Supplier name
</li>
<li>
#4833Supplier name
#4835Supplier name 2
</li>
<li>
#4833Supplier name
#4835Supplier name 2
#4840Supplier name 3
</li>
Never clearing the buffer between block invocation. What am I missing here?
(Riding on Rails 3.2.22)
I don't have much experience with Rails 3.2; with newer versions, you're able to pass collections to partials:
<%= render #pos, layout: 'today_items_list' %>
#app/views/pos/_today_items_list.html.erb
.tableless_cell.no_padding
%h3.no_margin_vertical= title
%ul.no_margin_vertical
<%= yield %>
#app/views/post/_po.html.erb
<%= link_to "##{po.id}", po %>
<%= po.supplier.name %>
You can read more about collections etc (I presume for Rails 4+) here.

update partial with object content in rails 4

Well, i have a problem, and i was wondering if it could be solved with rails only.
I have setup a view (home.html.erb) vith 3 partials, like this:
<%provide :title, 'Reader'%>
<div class = "row">
<div class = "span4">
<div class = "row">
<%= render 'layouts/add_subscription'%>
</div>
<div class = "row">
<%= render 'layouts/subscription_list'%>
</div>
</div>
<div class = "span8">
<div class = "row">
<%= render 'layouts/view' %>
</div>
</div>
</div>
where subscription_list shows up a list of links pointing to the list action after a redirection, each of them with the id of the subscription:
<ul>
<% current_user.subscriptions.each do |s| %>
<li><%= link_to s.url, "/list?s_id=#{s.id}" %></li>
<% end %>
</ul>
So, each of these links points to the list action in the controller, which tries to fetch the feed list of the subscription just clicked, and update the home view with the list of titles for the selected subscription:
def list
s_id = params[:s_id]
feed = ""
if !s_id.blank?
s = Subscription.find_by(id: s_id)
feed = Feedzirra::Feed.fetch_and_parse(s.url)
#render partial: "layouts/view", :locals => {:f => feed}
end
The problem is that I'm stuck at this point. I've tried to do a redirect_to home_path with feed as a parameter, and even a render (the line before the end of the list method) to see what happened, but nothing updates 'just' the layouts/view partial:
<ul>
<% if defined? feed and !feed.blank? %>
<% f.entries.each do |entry|%>
<li><%= entry.title %></li>
<% end %>
<% end %>
</ul>
So, I was wondering if it's possible to update the partial and see the result after a page reload using only rails methods, or if it can/must be done using javascript, and a clue to how to do this. Thanks in advance.
The goal you want to achieve is to show feed entries in the home.html.erb after clicking a link.
You can do it by pointing your links to the home action instead of list so that rails will automatically render your home.html.erb view and
you have to assign the instance variable #feed so it will be visible in your view.
You can do it like this (refactored a bit):
controller
def home
s_id = params[:s_id]
if s_id.present?
s = Subscription.find_by(id: s_id)
#feed = Feedzirra::Feed.fetch_and_parse(s.url)
end
end
layout/view
<ul>
<% if #feed.present? %>
<% #feed.entries.each do |entry|%>
<li><%= entry.title %></li>
<% end %>
<% end %>
</ul>
I'm not sure what is the path to your action, I assume here that home is the root ("/")
layouts/subscription_list
<ul>
<% current_user.subscriptions.each do |s| %>
<li><%= link_to s.url, "/?s_id=#{s.id}" %></li>
<% end %>
</ul>

How to prepend a new li element into content_tag_for block with jQuery

I'm trying to write a coffeescript to prepend a new element into a content_tag_for block. And if possible using a partial for code simplicity sake.
<ul id="documents">
<% #documents.each do |document| %>
<%= content_tag_for :li, document do %>
<%= document.title %>
<%= document.position %>
<%= link_to 'Delete', document, method: :delete, remote: true %>
<% end %>
<% end %>
</ul>
And my create.js.coffee attempt. But using a partial caused issues because when I run this, the element is added without a wrapping, breaking sorting and stylizing behavior until after a page reload. I want to append the new record asynchronously using jQuery of course.
$('<%= escape_javascript(render(:partial => #document))%>')
.prependTo('#documents')
.hide()
.fadeIn()
$('#new_document')[0].reset()
Solved.
my updated create.js.coffee
$('<%= content_tag_for :li, #document do %>
<%= render #document %>
<% end %>')
.prependTo('#documents')
.hide()
.fadeIn()
$('#new_document')[0].reset()

click link inside li tag

<li id="tab1">
<%= link_to_remote .... %>
</li>
I am trying to click this link using prototype like
<% javascript_tag do %>
$$('#tab1 a').click();
<% end %>
<% javascript_tag do %>
$$('#tab1 a').simulate('click');
<% end %>
but everything failed.
In Prototype there is no Element.click so that cannot work. There is an Element.simulate but it's non-standard, you have to add the event.simulate.js library yourself.
$$() returns an array so you need to get an element either like $$('#tab1 a')[0] or more safely with invoke().
$$('#tab1 a').invoke('simulate', 'click');

Resources