I have a Rails 3.2.19 app that I'd like to track vehicles (Units) with using geocoding and plotting on Google Maps.
I came up with a way to get coordinates by using the taip_parser gem and creating a rake task that constantly listens for inbound taip data, parses the latitude and longitude and updates the vehicle model's latitude and longitude fields. From there I was able to plot vehicle locations using the gmaps4rails gem. The limitation of this is that you have to use a specific 3G/4G modem that speaks in TAIP to send the lat/long to the Rails server so the rake task can parse it.
What I'd like to do is to negate having to use these expensive 3G/4G modems and instead pull the coordinates from a mobile device located in the vehicle (currently an iPad).
So my thoughts are to use the HTML5 Geolocation feature in the browser to obtain the latitude and longitude of the unit and somehow store that into the Unit's latitude/longitude database fields upon page/partial refresh which happens currently via Ajax.
This would break the dependence on the the existing devices and allow any mobile GPS enabled device to be compatible with this feature.
Currently in my app I have gmaps4rails to plot the units using my rake task and taip data parsing and also geocoder which I'm testing to geocode addresses as they are created for another purpose.
My questions are:
Can someone provide an example of how to use the HTML5 geolocation feature in a rails view? Once HTML5 geolocation is enabled in the view, how to get the latitude and longitude into the respective models latitude and longitude fields? Perhaps an example iteration of multiple objects' latitude longitude using gmaps4rails
If my question is too vague or convoluted please let me know so I can edit it and make things more clear as to what I'm trying to do.
I was able to get this working by using some ajax and a custom controller action in my Rails app. Using Ajax and a hidden form, I pull the coordinates using HTML5, populate the form with the values, and to an ajax post submit.
See below for the code:
controller
def update_gps
#unit = current_user.unit
if #unit.update_attributes(params[:unit])
respond_to do |format|
format.html {redirect_to mdt_path}
format.js { render "index"}
end
end
end
index.html.erb
<div class="hidden">
<%= form_for(#unit, :url => update_gps_mdt_index_path, :html => {:method => :post}) do |f| %>
<%= f.text_field :latitude %>
<%= f.text_field :longitude %>
<%= f.button :submit %>
<% end %>
</div>
<script>
$(function() {
setInterval(function(){
$.getScript("/mdt");
}, 10000);
});
function updateCurrentLocation(){
navigator.geolocation.getCurrentPosition(function(position) {
var c = position.coords
var location = c.latitude +", "+ c.longitude
console.log(location)
var $updateLocationForm = $(".edit_unit")
$("#unit_latitude").val(c.latitude)
$("#unit_longitude").val( c.longitude)
var data = $(".edit_unit").serialize();
console.log(data)
$.ajax({
type: "POST",
url: $(".edit_unit").attr("action"),
data: data,
success: function(data) {
console.log('working: '+data);
},
error: function(msg) {
console.log('not working '+msg);
}
});
});
}
setInterval(updateCurrentLocation, 10000)
</script>
Related
I have a form I want to submit automatically whenever any input field is changed. I am using Turbo Streams, and if I use onchange: "this.form.submit()" it isn't captured by Turbo Streams and Rails uses a standard HTML response. It works fine when clicking the submit button. How can I work around this?
There is a discussion on the hotwire forum, where Mark Godwin figured out why form.submit() isn't working with turbo:
Turbo intercepts form submission events, but weirdly, the JS formElement.submit() method does not trigger the submit event.
And Jacob Daddario figures out that you can use form.requestSubmit() instead:
It turns out that the turbo-stream mechanism listens for form submission events, and for some reason the submit() function does not emit a form submission event. That means that it’ll bring back a normal HTML response. That said, it looks like there’s another method, requestSubmit() which does issue a submit event.
So you can change your code slightly, and use requestSubmit() if a browser supports it, and use submit() if not:
onchange: "this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit()"
Update:
As BenKoshy pointed out, in Turbo 7.1.0, a polyfill was added so you can use form.requestSubmit() without checking for browser support, so you can add this to your input field:
onchange: "this.form.requestSubmit()"
I need to implement this for an app with lots of forms. I wound up using Stimulus. Below is the whole controller:
import { Controller } from "stimulus"
const _ = require("lodash")
export default class extends Controller {
connect() {
let that = this;
that.element.addEventListener('change', _.debounce(that.handleChange, 500))
}
handleChange(event) {
event.preventDefault()
// event.target.name // => "user[answer]"
// event.target.value // => <user input string>
event.target.form.requestSubmit()
}
}
and here it's used in a form with a single text input. NOTE the controller is attached to the form, not to the inputs.
<%= turbo_frame_tag dom_id(form_model) do %>
<%= form_with model: form_model,
format: :turbo_stream,
html: { data: { controller: "buttonless-form" } } do |f| %>
<%= f.hidden_field :question_id, value: question.id %>
<%= f.text_field :answer_value, class: "input shadow wide", placeholder: "Enter your answer here" %>
<% end %>
<div id=<%= "question_#{question.id}_output" %>>
<p> <!-- feedback to the user shows up here via Turbo -->
</div>
<% end %> <!-- end turbo frame -->
We use a fields_for and jquery to add a partial view on a form in rails 3.2 app. Here is the code:
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render :partial => association.to_s, :locals => {:f => builder, :i_id => 0}
end
link_to_function(name, "add_fields(this, \"#{association}\", \"#{j fields}\")")
end
In applicaton.js:
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g")
$(link).parent().before(content.replace(regexp, new_id));
}
Whenever the 'Add Field' link is clicked, the partial view is rendered and a few input fields are added to the current form. The code works in execution without any problem. However in integration test (capybara & launchy), the click_link('Add Field') did not do anything and failed bringing up the partial. Is jquery not enabled in integration test?
By default Capybara use :rake_test driver on all tests, which is fast but dosen't support JavaScript.
Since this test needs JavaScript, make sure you have turned JS driver on.
describe "some feature", js: true do
# test code
end
This will use default JS driver Selenium.
Hi I am currently working on a trash bin/recycling bin location application using google maps for rails.
I have a recyclingbin.rb model with the address as its attributes, that itself is enough to put markers on a map that can get displayed using the gem. I believe the gem converts the model and its attributes into json data.
I am trying to implement a feature where I can input my location and get direction to the nearest marker.
I have looked at the wiki , https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Direction
Am I suppose to put this in the view ?
{ "data" => { "from" => "Paris, france", "to" => "Toulon, france" } }
})
%>
with the from to be embedded with my location for now? I understand I can pass options to this reference from google.
The wiki is quite short, can someone give me a quick explanation ?
The wiki does need some more work. I have a simple app working that shows the directions on the map from a location to another (pre-defined) location
<%= gmaps("map_options" => {"zoom" => 14}, "markers" => { "data" => #json },
"direction" => { "data" => {"from" => #location.address, "to" => "New York City"},"travelMode" => "DRIVING"}) %>
I just put this in my view. It shouldn't matter where, just as long as its there. Hope this helps
I have a vote model with "like", "dislike" actions. I have a route for each of these actions. When I call the actions, I'm returning a json response. My problem is that first, I need to figure out how to send the query to my like/dislike actions. I need to access ruby/rails variables from my javascript (I'm sending an ajax request using jquery's $.getJSON), so that for example I can create the request for the correct item. Help much appreciated.
A popular technique is to attach data to the dom. For example (pseudocode follows):
<% items.each do |item| %>
<div class="like_button" data-item-id="<%= item.id %>">Like</div>
<% end %>
and in the JavaScript:
$(".like_button").on("click", function() {
var item_id = $(this).data('item-id'); // from the dom
// construct Ajax request for item_id
});
I am using Rails + Backbone + Faye to make a sample chat application.
I'm currently able to use Faye's messaging capabilities to write to the DOM on a create event, though I'm not actually instantiating a backbone model. Ala Ryan Bates' tutorial I'm just calling inside of
create.js.erb
<% broadcast "/messages/new" do %>
$("#chats-table").append("<%= escape_javascript render :partial => "chat", :locals => { :chat => #chat } %>");
<% end %>
And publishing it in another javascript:
faye.subscribe("/messages/new", function(data) {
eval(data);
});
I'd like to refactor this a bit and leverage backbone's models. A good use case would be the delete method.
My chat model is bound to a click event, delete which calls:
model.destroy();
this.remove();
Backbone will call the delete method and put a delete request to /entity/id
That also dispatches rails' /views/delete.js.erb'.
In there I call a helper method which publishes a message with Ruby code.
<% broadcast "/messages/delete" do %>
<%= #chat.to_json.html_safe; %>
<% end %>
listener
var faye = new Faye.Client('http://0.0.0.0:9292/faye');
faye.subscribe("/messages/delete", function(data) {
});
Here, I was wondering if i could instantiate the deleted backbone model somehow so I could push that event onto everybody's screen and remove it from the DOM. Basically, I would like to call this.remove(); inside the faye client instead of in the chat model. Is this even possible?
Well, you should do remove on the model and let the UI listen for the event and refresh itself. Once the UI reflects the model changes you are golden.
The problem you have here is that Backbone collections/models are not an identity map. So the model object you are dealing with in the view is not the same you will instantiate and remove from the faye callback. If your messages collection is globally accessible, then I suggest you get the instance from there are remove it.