Rails Dev environment with Javascript and Ajax - javascript

There's something I definitely don't understand going on in the background in dev.
I have an app which I've been developing locally on my Mac, and it has a form which makes an Ajax call "remote: true". It stopped working, no Ajax call, nothing in the logs.
The only way I could get it to start working again was to edit my _form.html.erb partial by adding a second input field (identical to the original, straight copy and paste). Refresh the page, then it worked. I've unedited my original edit, so the code is back to where it originally was (when it was not working), but now it's working.
What does the edit cause to happen? Is there someway I can cause it to happen without editing my code?
Thanks.
----- EDIT adding code -----
My form is (the text_field_tag is what I copied and pasted)
<div id="friend-lookup">
<h3>Search for friends</h3>
<%= form_tag search_friends_path, remote: true, method: :get, id: 'friend-lookup-form' do %>
<div class="form-group row no-padding text-center col-md-12">
<div class="col-md-10">
<%= text_field_tag :search_param, params[:search_param],
placeholder: "first name, last name or email", autofocus: true,
class: 'form-control search-box input-lg' %>
</div>
<div class="col-md-2">
<%= button_tag(type: :submit, class: "btn btn-lg btn-success") do %>
<i class="fa fa-search"></i> Look up a friend
<% end %>
</div>
</div> <!--- form-group -->
<% end %>
<%= render 'common/spinner' %>
<% if #users %>
<% if #users.size > 0 %>
<div id="friend-lookup-results" class="well results-block col-md-10">
<table class="search-results-table col-md-12">
<tbody>
<% #users.each do |user| %>
<tr>
<td><strong>Name:</strong> <%= user.full_name %></td>
<td><strong>Email:</strong> <%= user.email %></td>
<td><strong>Profile:</strong> <%= link_to "View Profile", user_path(user),
class: "btn btn-xs btn-success" %>
<% if current_user.not_friends_with?(user.id) %>
<%= link_to "Add as my friend", add_friend_path(user: current_user, friend: user),
class: "btn btn-xs btn-success", method: :post %>
<% else %>
<span class="label label-primary">
You are friends
</span>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<p class="lead col-md-12">
No people match this search criteria
</p>
<% end %>
<% end %>
<div id="friend-lookup-errors"></div>
</div>
And the javascript is
# assets/javascript/friends.js
var init_friend_lookup;
init_friend_lookup = function() {
$('#friend-lookup-form').on('ajax:before', function(event, data, status){
$('#friend-lookup-results').replaceWith(' ');
show_spinner();
});
$('#friend-lookup-form').on('ajax:after', function(event, data, status){
hide_spinner();
});
$('#friend-lookup-form').on('ajax:success', function(event, data,status){
$('#friend-lookup').replaceWith(data);
init_friend_lookup();
});
$('#friend-lookup-form').on('ajax:error', function(event, xhr, status, error){
hide_spinner();
$('#friend-lookup-results').replaceWith(' ');
$('#friend-lookup-errors').replaceWith('Person was not found.');
});
}
$(document).ready(function() {
init_friend_lookup();
});

You may be used to installing JavaScript behavior in response to the window.onload, DOMContentLoaded, or jQuery ready events. With Turbolinks, these events will fire only in response to the initial page load—not after any subsequent page changes.
Change the "ready" event for 'turbolinks:load', and repeat the same step with you all events.
$(document).on('turbolinks:load', function () {
init_friend_lookup();
});
Read the documentation, https://github.com/turbolinks/turbolinks

Maybe this will help someone out there.
I am running Rails 5.
What was tricky was that it seemed intermittent.
My problem seems to be turbolinks related. Removing turbolinks, in javascript/application.js
//= require turbolinks
seems to have fixed the problem consistently.

Related

How to make additional forms with with new objects using Javascript/jQuery?

On initial page load, all of the current user's highlights are gathered and each is put into a form. These forms are later shown the user once he clicks a certain button.
The scenario I'm trying to sort out, though, is that through the course of the user's interactions, new highlights can be created. And these new highlights also need to be 'prepared' within the same series of forms.
At the moment, I'm trying to use a gigantic .append() method, but it's failing silently in the background.
Any pointers? I suspect it may have something to do with improper quotation management within the method call and/or incorrect usage of the "j" escape_javascript Rails method...
Is there a better way of approaching the scenario? I've tried 'refreshing' the div with a call to render the partial. While that does achieve the end result of having "current" data on display, the problem there is the associated *.js file becomes 'disconnected' from the page, ruining the user interactions.
Thank you in advance for any help or insight you can offer!
_partial.html.erb This is what I'm essentially trying to 'add to'
<% #current_user_highlights.each do |highlight| %>
<div class="slide">
<%= form_for(highlight, remote: true) do |f| %>
<%= f.fields_for :image_tags_attributes do |image_tag_fields| %>
<%= image_tag_fields.fields_for :tag_content_attributes do |tag_content_attributes_fields| %>
<%= image_tag highlight.file_url(:speck), data: { src: highlight.file_url(:medium),
id: highlight.id } %>
<div class="wrapper">
<%= tag_content_attributes_fields.text_field :content, class: 'form-control',
id: "tag-content-field-#{highlight.id}" %>
<%# id: "tag-content-field-#{highlight.parent_image.id}" %1> %>
<div class="actions display-none">
<%= button_tag "", type: 'submit',
class: "btn btn-lg btn-default glyphicon glyphicon-ok above-interaction-barrier",
id: "highlight-confirmation-submit-button-#{highlight.id}" %>
<%= button_tag "", class: "btn btn-lg btn-default glyphicon glyphicon-remove above-interaction-barrier",
id: "highlight-confirmation-remove-button-#{highlight.id}" %>
<%= button_tag "Skip", class: "btn btn-med btn-default above-interaction-barrier display-none skip-button",
id: "highlight-confirmation-skip-button-#{highlight.id}" %>
</div>
</div>
<% end %>
<%= image_tag_fields.fields_for :tag_title_attributes do |tag_title_attributes_fields| %>
<%= tag_title_attributes_fields.hidden_field :title, value: highlight.tag_titles.first.title %>
<% end %>
<% end %>
<% end %>
</div>
<% end %>
update.js.erb
$('#highlight-confirmation-wrapper div.slide:last').append(
"<div= 'slide' <%= j form_for(#image.crops.last, remote: true) do |f| %>
<%= f.fields_for :image_tags_attributes do |image_tag_fields| %>
<%= image_tag_fields.fields_for :tag_content_attributes do |tag_content_attributes_fields| %>
<%= image_tag #image.crops.last.file_url(:speck), data: { src: #image.crops.last.file_url(:medium),
id: #image.crops.last.id } %>
<div class="wrapper">
<%= tag_content_attributes_fields.text_field :content, class: 'form-control',
id: "tag-content-field-#{#image.crops.last.id}" %>
<%# id: "tag-content-field-#{highlight.parent_image.id}" %1> %>
<div class="actions display-none">
<%= button_tag "", type: 'submit',
class: "btn btn-lg btn-default glyphicon glyphicon-ok above-interaction-barrier",
id: "highlight-confirmation-submit-button-#{#image.crops.last.id}" %>
<%= button_tag "", class: "btn btn-lg btn-default glyphicon glyphicon-remove above-interaction-barrier",
id: "highlight-confirmation-remove-button-#{#image.crops.last.id}" %>
<%= button_tag "Skip", class: "btn btn-med btn-default above-interaction-barrier display-none skip-button",
id: "highlight-confirmation-skip-button-#{#image.crops.last.id}" %>
</div>
</div>
<% end %>
<%= image_tag_fields.fields_for :tag_title_attributes do |tag_title_attributes_fields| %>
<%= tag_title_attributes_fields.hidden_field :title, value: #image.crops.last.tag_titles.first.title %>
<% end %>
<% end %>
<% end %>
</div>");
I was able to get this sorted out by changing the approach I was using.
Rather than have the form partial include the call to #current_user_highlights, and thereby proceed to make numerous forms, I instead broke the form itself into a separate partial. This allows me to reuse the form later to 'render' a single instance based off of the highlight that is sent through along with the update.js.erb file.
I also added an additional wrapper around the slide listing, this allowed me to more easily use the .append() jQuery function.
The resulting update.js.erb file looks something like this:
$('#slides-wrapper').append("<div class='slide'> <%= j render 'tasks/highlight_confirmation_slide_form', highlight: #image.crops.last %> </div>");

Javascript not executing after Rails redirect

My application contains a very simple login and two separate AJAX calls. I have a loading spinner that is hidden automatically whenever a page is ready it is contained in index.js
$(function() {
$("loading").hide();
$("#scan_button").on("ajax:success", function(e, data, status, xhr) {
$("#standard_results").hide();
$("#results").show();
$("#results").html(data);
});
$(document).ajaxStop(function() {
$("#loading").hide();
});
$(document).ajaxStart(function() {
$('#loading').show();
});
});
When a user logs in the following happens
class SessionController < ApplicationController
def create
user = User.find_by(username: params[:session][:username])
if(user.password == params[:session][:password])
log_in user
redirect_to root_path
end
end
def destroy
logout
redirect_to root_path
end
end
The route path takes me back to 'home#index' for which the index.js file exists. When the user logs in the redirect happens and the loading spinner is hidden and all JavaScript executes as expected.
When the user hits log out however the redirect occurs, but the loading spinner is shown and no JavaScript ever gets executed. Here is my index.html.erb file that contains the JavaScript.
<% content_for :title, "Network Monitor" %>
<div class="container-fluid">
<nav class="navbar narvbar-dark bg-inverse">
<span class="navbar-brand">Network Monitor</span>
<%= link_to "Scan", scan_path, remote: true, class: "btn btn-secondary", id: "scan_button" %>
<% if logged_in? %>
<span class="pull-xs-right"><%= link_to "Logout", logout_path, class: "btn btn-secondary" %></span>
<% else %>
<%= form_for(:session, url: login_path, :html => {:class => 'form-inline pull-xs-right'}) do |f| %>
<%= f.text_field :username, class: 'form-control', placeholder: "Username" %>
<%= f.password_field :password, class: 'form-control', placeholder: "Password" %>
<%= f.submit "Log in", class: 'btn btn-primary', id: 'login_button' %>
<% end %>
<% end %>
</nav>
<div id="loading">
<%= image_tag "loading.gif", class: "loading_gif" %>
</div>
<div class="row">
<div class="col-md-12">
<div id="scan_bar">
<h3>Welcome to your network monitor!</h3> <br />
<p>To get started hit the scan button in the top right corner, this will detect the computers that are alive on your network and show them below.</p>
</div>
</div>
</div>
<div class="row">
<div id="results">
</div>
<div id="standard_results">
</div>
Solved. It was as simple as using
$(document).on('turbolinks:load', function() {});
Instead of what I had posted, this seems to be the way that Rails 5 and turbolinks want you to use, and it worked.
According to the
turbolinks document, I use the event page:change to solve the problem:
$(document).on("page:change", function(){...});
It works for me.
In case others run into this. If you are using an href or link_to try doing something like this:
<li><%= link_to "Home", jobs_path, method: :get %></li>
...where you specify the get method in the request.

Rendering a partial to an edit form inside a popover in rails 4

Hi guys I really need help here.
I'm making a todo app and displaying each task through an iteration. Next to each task I have a pencil glyphicon.
When I click on it, I want there to be a popover containing an edit form and edit the task on the spot. I'm having a ton of troubling rendering that form.
***** UPDATE *****
Clark helped me get the popover to work. But The form inside the popover is acting like a link instead of a form so I can't type in the text area.
This is my index.html.erb
<div id='user_tasks'>
<% #tasks.each do |task| %>
<ul>
<li>
<%= task.description %>
<%= link_to edit_task_path(task), :rel => 'popover', method: 'get', remote: 'true' do %>
<span class = 'edit_task_<%=task.id%> glyphicon glyphicon-pencil'> </span>
<% end %>
</li>
</ul>
<% end %>
</div>
This is the edit.js.erb
$(function(){
$('.edit_task_<%=#task.id%>').popover({
html: true,
title: 'edit',
content: <%= escape_javascript render 'edit_form', task:#task %>
}).popover('show'); });
and my controllers look like this:
def index
#new_task= Task.new
#tasks= Task.all
end
def create
#new_task= Task.new(task_params)
#task.save
redirect_to :back
end
def edit
#task= Task.find(params[:id])
end
_edit_form.html.erb looks like this: This isn't the edit form that I plan to use. Its just a copy of the create task form. I plan to fix it once I get the popover working.
<%= form_for task, :html=>{:class=> 'form-inline'} do |f| %>
<div class='form-group'>
<%= f.text_field :description, placeholder: 'create a task' %>
<%= button_tag(type:'submit', class:"btn btn-default btn-xs") do %>
<span class='glyphicon glyphicon-plus'></span>
<% end %>
</div>
<% end %>

How to make items on a rails form sortable

Using Rails 4 and Ruby 1.9.3. Styling is handled by an internally developed gem based on bootstrap 3.
I've been looking around for answers to this and have found a number of different examples that show how to do this with a basic list in a view. The railscast is one such example I've looked at.
http://railscasts.com/episodes/147-sortable-lists
However, I am trying to achieve this in a rails nested form using a partial but having no success. Sadly I am new to ruby, rails and have no prior knowledge of javascript so this is all a step learning curve.
My service model relates to a places model through service places. The service_places.position field holds the order of the stops.
My nested form (_form.html.erb) for services is shown below:
<!-- Adds the Service_Places (stops) associations via partial (sort applied in model) -->
<div>
<div class="links" id="sortable">
<%= link_to_add_association 'Add Stop', f, :service_places, :class => "btn btn-default", :data => {"association-insertion-method" => "after" } %>
</div>
<%= f.fields_for :service_places do |service_places| %>
<%= render 'service_place_fields', :f => service_places %>
<% end %>
</div>
My service_place partial is shown below:
<!-- This will hold the partial form for service places -->
<div class="nested-fields">
<%= f.label :service_place, "Stops", :class=>"col-sm-2 control-label" %>
<div class="col-sm-1">
<%= f.text_field :position, :class=> "form-control", :placeholder => "Position" %>
</div>
<div class="col-sm-3">
<%= f.collection_select :place_id, Place.where('active = true').order(:place_name), :id, :place_name, :prompt => "Select Place" %>
</div>
<div>
<%= link_to_remove_association "Remove Stop", f, :class => "btn btn-default" %>
</div>
</div>
I started looking at trying to assign an ID to each of the service_place partials DIV tags but couldn't get it to work.
The questions I would like to know are:
1) Is it possible to allow user to reorder items within forms? and save the new order in the server?
2) If it is possible could someone give me a hint on how to go about doing this.
Thanks in advance for taking time to look at this post.
My colleague showed me a way to achieve this using the "acts as list" gem.
His blog can be found here:
http://nicholshayes.co.uk/blog/?p=344
To get this working I made the amendments as shown below.
1) In my service model I added these three methods:
# Used in the positioning of service places using the acts_as_list gem
def method_missing(symbol, *args, &block)
if acts_as_list_method?(symbol)
pass_method_to_service_service_place(symbol, args.first)
else
super
end
end
# Used in the positioning of service places using the acts_as_list gem
def pass_method_to_service_service_place(symbol, service_place)
raise "A Service_Place is needed for re-ordering places" unless service_place.kind_of? ServicePlace
service_place.send(symbol) if service_place
end
# Used in the positioning of service places using the acts_as_list gem
def acts_as_list_method?(symbol)
ActiveRecord::Acts::List::InstanceMethods.instance_methods.include?(symbol.to_sym)
end
2) Added route's
resources :services, :concerns => :paginatable, only: [:create, :destroy, :edit, :index, :new, :show, :update] do
# Required for the re-ordering of the routes
resources :service_places do
member do
get :move_up
get :move_down
end
end
end
3) Amend the SERVICE show.html
<% #service.service_places.reorder("service_places.position asc").each do |serviceplace| %>
<dd>
<% if user_signed_in? %>
<% if #service.first?(serviceplace) %>
<%= link_to('', move_up_service_service_place_path(serviceplace, service_id: #service), class: "btn btn-default btn-xs glyphicon glyphicon-arrow-up invisible") %>
<% else %>
<%= link_to('', move_up_service_service_place_path(serviceplace, service_id: #service), class: "btn btn-default btn-xs glyphicon glyphicon-arrow-up") %>
<% end %>
<% if #service.last?(serviceplace) %>
<%= link_to('', move_down_service_service_place_path(serviceplace, service_id: #service), class: "btn btn-default btn-xs glyphicon glyphicon-arrow-down invisible") %>
<% else %>
<%= link_to('', move_down_service_service_place_path(serviceplace, service_id: #service), class: "btn btn-default btn-xs glyphicon glyphicon-arrow-down") %>
<% end %>
<% end %>
<!-- Unfortunately this is not very efficient way of showing the place because it calls the db for each item. -->
<%= Place.find(serviceplace.place_id).place_name %>
</dd>
<% end %>

Rails 3 coffeescript controller association?

Alright, I'm a JS / JQuery / Coffeescript noob. This is probably easy points for someone.
Having successfully implemented RBate's Nested Form Model railscast, I am attempting to reproduce this in a simpler model: Chapters have many counties.
I have a chapters.js.coffee file with the following code:
jQuery ->
$('form').on 'click', '.remove_fields', (event) ->
$(this).prev('#destroy').val('1')
$(this).closest('fieldset').hide()
event.preventDefault()
This code works just fine in the other model. But not here.
_chapters_form.html.erb:
<div class="row span12">
<%= form_for(#chapter) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="span2"><strong>Chapter name:</strong></div>
<div class="span6"><%= f.text_field :name %></div>
<div class="span2"><strong>Chapter Number:</strong></div>
<%= f.number_field :chapter_num, class: "span2" %>
</div>
<div class="row span12">
<div class="span12">
<%= f.fields_for :counties do |builder| %>
<%= render 'county_fields', f: builder %>
<% end %>
</div>
<% if f.object.new_record? then link = 'Add the Chapter' else link = 'Update Chapter' end %>
<%= f.submit "#{link}", class: "btn btn-large btn-primary" %>
<%= link_to "Cancel", chapters_path, class: "btn btn-large btn-primary" %>
<% end %>
</div>
and:
_county_fields.html.erb:
<fieldset>
<div class="well span12">
<div class="row span12">
<div class="span3">County Number: <br /><i>(6-digit FIPS code)</i></div>
<div class="span2"><%= f.number_field :county_num %></div>
<div class="span2">County Name:</div>
<div class="span5"><%= f.text_field :name %></div>
</div>
<div class="row span12"><hr></div>
<div class="row span12">
<div class="span6">Move to new Chapter:</div>
<div class="span6"><%= select(:county, :chapter_id, Chapter.all.collect {|c| [c.name, c.id]}) %></div>
</div>
<div class="row span12">
<div class="pull-right">
<%= f.hidden_field :_destroy, id: "destroy" %>
<%= link_to "remove county", "#", class: "remove_fields" %>
</div>
</div>
</div>
</fieldset>
There are no errors in the JS. Again, noob speaking, but it doesn't seem that the JS is getting called. Clicking <%= link_to "remove county", "#", class: "remove_fields" %> just adds the # to the URI.
What am I doing wrong?
As requested, the HTML in a fiddle which doesn't work either.
Your HTML is broken. You open a div before the form element, then close it before you close the form. If you move the form element up to just inside the container div, it works.
<body>
<div class="container-fluid">
<form accept-charset="UTF-8" action="/chapters/7" class="edit_chapter" id="edit_chapter_7" method="post">
<div class="row-fluid">
...
</div>
</form>
</div>
</body>
You should take more care in the indenting of your HTML to help avoid this sort of simple mistake. Code format matters.
The page on which they appear - regardless of how they are rendered - must be an action of the chapters_controller for chapters.js.coffee to be included. My bet is that the script is not being included at all, as the code looks fine. Check out the pages you are having issues with with this code:
jQuery ->
console.log "included chapters.js.coffee"
$('form').on 'click', '.remove_fields', (event) ->
console.log "clicked .remove_fields"
$(this).prev('#destroy').val('1')
$(this).closest('fieldset').hide()
event.preventDefault()
Also, post up the rendered HTML in your question

Categories