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
Related
I'm trying to render the following partial:
<% #accepted.each do |question| %>
<div class="questions-container__content">
<div class="questions-container__accepted-content">
...
</div>
<%= render 'question_buttons', collection: #accepted %>
</div>
<% end %>
with _question_buttons.html.erb:
<div class="links-container__button-group" id="link-buttons">
<%= link_to "View submission", coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<%= link_to "Edit", edit_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% if !question.accepted? %>
<%= link_to "Activate" , activate_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% else %>
<%= link_to "Deactivate" , deactivate_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% end %>
<% if current_user.admin? %>
<%= link_to (question.rejected ? "Restore" : "Reject"), reject_coin_question_path(question.coin, question.id), class: "primary-small","data-turbolinks"=>"false" %>
<% end %>
</div>
I get the following error:
undefined local variable or method `question' for #<#<Class:0x00007fece6998d08>:0x00007fed02072bb8>
What am I doing wrong here?
I believe the issue is that you need to pass the question variable from each loop in the parent view through to the partial using locals which allows the partial to access it.
<%= render 'question_buttons', locals: { question: question } %>
First:
When rendering a collection, each item of the collection is passed to the partial as a local variable with the same name as partial itself. It means that for this call:
<%= render 'question_buttons', collection: #accepted %>
the partial question_buttons will be called for each item of #accepted array; that item will be available inside partial as question_buttons.
If you want to use another name for the item, for example question, you need to call it as:
<%= render 'question_buttons', collection: #accepted, as: :question %>
Another option -- just rename the partial to question:
<%= render 'question', collection: #accepted %>
Second:
In your code snippet rendering collection is called on each iteration of the loop over #accepted elements. If #accepted has 8 elements, for example, the partial will be rendered 8 times for each of these elements, ie 8 * 8 = 64 times in total. I suspect that it's not what you want to achieve. Your code looks like question_buttons partial needs to be rendered for each element of #accepted only once. In this case using collection param has no sense here. Just pass a local variable question into the partial:
<%= render 'question_buttons', question: question %>
I have Challenges containing Puns, and it is possible to vote on puns. On the Challenge Show page, all puns are rendered and show their votes count. This is currently on the view page:
<%= render #challenge.puns.reverse %>
<br>
<div id="form">
<%= render "puns/form" %>
</div>
I want the puns form to appear above the items (puns) already submitted. But if swap them around, like this:
<div id="form">
<%= render "puns/form" %>
</div>
<%= render #challenge.puns.reverse %>
I get a controller error and pun.id is not suddenly not available and the voting link breaks.
No route matches {:action=>"upvote", :challenge_id=>"9", :controller=>"puns", :id=>nil}, missing required keys: [:id]
Here is the puns/form part that is causing the issue
<% if signed_in? %>
<% if current_user.voted_for? pun %>
<%= pun.votes_for.size %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% else %>
<%= link_to like_challenge_pun_path(#challenge, pun.id), method: :put do %>
<span class="heart_like">❤</span> <%= pun.votes_for.size %>
<% end %>
<span class="pun_text"><%= link_to pun.pun_text, challenge_pun_path(#challenge, pun.id) %></span>
<% end %>
<% end %>
It is the like_challenge_pun_path that throws an error but I cannot understand why. I am declaring #challenge again here, so it should be able to get the id.
Here is the form for the puns:
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
<span class=".emoji-picker-container">
<%= f.text_area :pun_text, placeholder: "Add pun", data: { emojiable: true } %>
</span>
<%= f.submit %>
<% end %>
Also, here is my routes setup
resources :challenges do
resources :puns do
member do
put "like", to: "puns#upvote"
put "dislike", to: "puns#downvote"
end
end
end
and the corresponding action to upvote
def upvote
#pun = #challenge.puns.find(params[:id])
#pun.upvote_by current_user
redirect_to #challenge
end
Can anyone help?
I think the code is for the puns collection.
I assume the issue is that in the form you have something like:
#challenge.puns.build
So in #challenge.puns collection appears not persisted record (without id), so path for this model cannot be generated.
As a quick solution I suggest:
<%= render #challenge.puns.reverse.select(&:persisted?) %>
UPDATE:
As I assumed you have
<%= form_for([#challenge, #challenge.puns.build]) do |f| %>
You can also try:
<%= form_for([#challenge, Pun.new]) do |f| %>
Or solve it in the controller. But need to see controller code for it.
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
I am trying to create a form that takes values from a table of input boxes. The user can enter the values in this table manually, or upload an excel spreadsheet. All of this works fine, but I want the user to be able to import a spreadsheet, and have the data table updated without reloading the page. The primary model to store this information is a DataTable object.
views/data_tables/index.html.erb looks like this:
<div id="tabs" class="tabs-bottom">
<ul>
<li>Data Input</li>
<li>Data Display</li>
</ul>
<div class="tabs-spacer"></div>
<div id="tabs-1" class="tab_frame">
<%= render #data_table %>
</div>
<div id="tabs-2" class="tab_frame">
<%= render "data_display" %>
</div>
</div>
I am using a tabbed view from the Jquery-UI.
The partial, views/data_tables/_data_table.html.erb, looks something like this:
<%= nested_form_for #data_table, :remote => true do |f| %>
<div id="table_pane">
<table id="table_input" class="table_input">
<tbody>
<%= f.fields_for :financial_rows, :wrapper => false do |dr| %>
<tr class="fields">
<td>
<%= dr.link_to_remove "x", {:class => "btn btn-danger"} %>
</td>
<td class="month">
<%= dr.text_field :month, :value => (dr.object.month.to_i) %>
</td>
<td class="year">
<%= dr.text_field :year, :value => (dr.object.year.to_i) %>
</td>
<td class="currency">
<% # . . . %>
<% #Multiple fields omitted for brevity %>
<% # . . . %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= f.link_to_add "+", :financial_rows, :data => { :target => "#table_input" }, :class => "btn btn-success" %></br>
</div>
<%= f.submit :value => "Render Data" %>
<% end %>
<%= form_tag import_data_tables_path, multipart: true, remote: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import Spreadsheet" %>
<% end %>
The import form at the end is what I am having trouble with. In my controller, controllers/data_tables_controller.rb, my import method looks like this:
def import
#data_table = DataTable.new
if !params[:file].blank?
imported_file = params[:file]
spreadsheet = read_file(imported_file)
header = spreadsheet.row(2)
(3..spreadsheet.last_row).each do |i|
data = Hash[[header, spreadsheet.row(i)].transpose]
f_row = FinancialRow.new
f_row.attributes = data.to_hash.slice(*FinancialRow.accessible_attributes)
#data_table.financial_rows << f_row
end
respond_to do |format|
format.html { redirect_to #data_table}
format.js
format.json { render json: #data_table, location: #data_table}
end
#render('index')
else
flash[:error] = "Select a file for import"
#data_table.financial_rows.build
#render('index')
end
end
When I import a file without trying to use Ajax, the page reloads with the text fields of the data table fully populated, but when I try to use Ajax, the page just reloads without any updates to the data table. I have written a javascript file which theoretically should replace the div the datatable is in.
views/data_tables/import.js.erb contains:
$("#tabs-1").html("<%= escape_javascript(render(:partial => #data_table)).html_safe %>");
I've scoured stackoverflow for hours, reading posts on how to replace a rendered partial using Ajax, but I haven't found anything that has worked for me. I'm sure it is something simple I am overlooking, but I'm having a lot of trouble wrapping my head around how Ajax is implemented with Rails, and how and why one should use either format.html, format.js, or format.json.
I am using rails 3.2.12. Some noteworthy gems I am using is the 'nested_form' gem to handle the data_table form, and 'roo' to handle importing the spreadsheet.
I have almost done! but I have an issue, in my Controller file have this:
def show
#user = User.find(params[:id])
#posts = #user.posts.paginate(page: params[:page])
end
Then I have this piece of code in my file show.html.erb:
<div class="span8">
<%= render 'follow_form' if signed_in? %>
<% if #user.posts.any? %>
<h3>Microposts (<%= #user.posts.count %>)</h3>
<div id='posts'>
<div class='page'>
<ol class="microposts">
<%= render #posts %>
</ol>
</div>
</div>
<% end %>
</div>
At the bottom of this file, I have a Javascript code that I have taken from the tutorial: https://github.com/amatsuda/kaminari/wiki/How-To:-Create-Infinite-Scrolling-with-jQuery
In the same folder I have the file index.js.erb with:
$("#articles").append("<div class='page'><%= escape_javascript(render(#users)) %></div>");
$("#posts").append("<div class='page'><%= escape_javascript(render(#posts)) %></div>");
In a partial _posts.html.erb have this:
<div class='article'>
<%= image_tag(user.picture_url, :width => 50) %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</div>
The first one already works in my file index.html.erb, the problem is with the second piece of code, when I try to render the partial at #post, It brings the follow log:
**
'nil' is not an ActiveModel-compatible object that returns a valid partial path.
Extracted source (around line #2):
1: $("#articles").append("<div class='page'><%= escape_javascript(render(#users)) %></div>");
2: $("#posts").append("<div class='page'><%= escape_javascript(render(#posts)) %></div>");
**
How can I render that partial?
Thanks a lot :D
I usually use the .js.erb template to render the partial into a var then set it on the page using JS. Be sure to escape_javascript the template content otherwise you will get JS errors.
<% template_html = render :partial => '_feed_item.html.erb' %>
<%="$('div#content').html('#{escape_javascript(template_html)}</div>');" %>
I think the above should work in erb. I use HAML so mine looks like:
-template_html = render :partial => 'partial_template'
!="$('div#content').html('#{escape_javascript(template_html)');"
Cheers.
Based on your In script I'm calling to /users?page=, and I was wondering that It may calls the line, you must make sure that your controller is populating the #posts variable if your view is using this. Can you show the controller method users?