Displaying a polygon with gmaps4rails - ruby-on-rails

Ruby noob here. Trying to display a list of points as a polygon on a google map using the gmaps4rails gem (awesome gem by the way). Any suggestions based on code sample below would be much appreciated! I can see the outline for the map, but no map and no polygon. Update: this code has been updated and the problem is solved.
Class Schoolpoint is a list of lat/long pairs that belong to School
In my controller:
#polyjson = []
schoolpoints = []
Schoolpoint.where(:school_id => params[:id]).each do |point|
schoolpoints << { :lng => point.longitude, :lat => point.latitude}
end
#polyjson = [schoolpoints]
#polyjson = #polyjson.to_json
Then in the view:
<%= gmaps({"polygons" => { "data" => #polyjson }})
in Schoolpoint model:
class Point < ActiveRecord::Base
belongs_to :place
acts_as_gmappable :process_geocoding => false
def gmaps4rails_address
"#{longitude}, #{latitude}"
end
end
Update: This error now longer exists, but I've left it in case its helpful to someone dealing with similar problem. Finally, here is the resulting js with an uncaught Syntaxerror => unexpected token.
Gmaps.map = new Gmaps4RailsGoogle();
Gmaps.load_map = function() {
Gmaps.map.initialize();
Gmaps.map.polygons = [[{"lng"=>-80.190262, "lat"=>25.774252, "strokeColor"=>"#FF0000", "strokeOpacity"=>0.3, "strokeWeight"=>1, "fillColor"=>"#FF0000", "fillOpacity"=>0.7}, {"lng"=>-87.6245284080505, "lat"=>41.8868315803506}, {"lng"=>-87.6241636276245, "lat"=>41.8674515900783}, {"lng"=>-87.6203870773315, "lat"=>41.8674835487326}, {"lng"=>-87.6167392730712, "lat"=>41.8579591627635}, {"lng"=>-87.6348495483398, "lat"=>41.8577034549953}, {"lng"=>-87.6342701911926, "lat"=>41.8588701133785}, {"lng"=>-87.6341199874878, "lat"=>41.858946025344}, {"lng"=>-87.6341146230697, "lat"=>41.8590858629394}, {"lng"=>-87.6341199874878, "lat"=>41.8600767034266}, {"lng"=>-87.6342219114303, "lat"=>41.8612433185139}, {"lng"=>-87.634157538414, "lat"=>41.8613112372298}, {"lng"=>-87.6342540979385, "lat"=>41.8621502271823}, {"lng"=>-87.6341950893402, "lat"=>41.8622580965204}, {"lng"=>-87.6342433691024, "lat"=>41.8626336402037}, {"lng"=>-87.6341092586517, "lat"=>41.8630930789441}, {"lng"=>-87.6342326402664, "lat"=>41.8631010691539}, {"lng"=>-87.6342862844467, "lat"=>41.8651984646832}, {"lng"=>-87.6342165470123, "lat"=>41.865314318812}, {"lng"=>-87.6342540979385, "lat"=>41.865929540668}, {"lng"=>-87.6343238353729, "lat"=>41.8661652409794}, {"lng"=>-87.6343667507171, "lat"=>41.8664728485533}, {"lng"=>-87.6342701911926, "lat"=>41.866564731048}, {"lng"=>-87.6343882083892, "lat"=>41.8673317449823}, {"lng"=>-87.6344525814056, "lat"=>41.8680388278011}, {"lng"=>-87.6346457004547, "lat"=>41.8691693450993}, {"lng"=>-87.6346671581268, "lat"=>41.8696886572982}, {"lng"=>-87.6345813274383, "lat"=>41.8698804022745}, {"lng"=>-87.6347583532333, "lat"=>41.869992253245}, {"lng"=>-87.634892463684, "lat"=>41.8706873227465}, {"lng"=>-87.6353269815445, "lat"=>41.8726167002032}, {"lng"=>-87.6352626085281, "lat"=>41.8728443868687}, {"lng"=>-87.6354557275772, "lat"=>41.8730081609862}, {"lng"=>-87.6353698968887, "lat"=>41.8732797854267}, {"lng"=>-87.6356971263885, "lat"=>41.8740227522642}, {"lng"=>-87.6356971263885, "lat"=>41.8746458790817}, {"lng"=>-87.6359224319458, "lat"=>41.87509724279}, {"lng"=>-87.6361316442489, "lat"=>41.8754088017203}, {"lng"=>-87.6364105939865, "lat"=>41.8754727110567}, {"lng"=>-87.6364642381668, "lat"=>41.8757642965932}, {"lng"=>-87.6371240615844, "lat"=>41.876678987795}, {"lng"=>-87.637939453125, "lat"=>41.8801059676767}, {"lng"=>-87.6379930973053, "lat"=>41.8806172030015}, {"lng"=>-87.6378536224365, "lat"=>41.8829017358812}, {"lng"=>-87.6375961303711, "lat"=>41.8844593251054}, {"lng"=>-87.6372849941253, "lat"=>41.8857213439117}, {"lng"=>-87.6371347904205, "lat"=>41.8860408383893}, {"lng"=>-87.6355576515197, "lat"=>41.8870552227663}, {"lng"=>-87.6282513141632, "lat"=>41.8870951588295}, {"lng"=>-87.6281654834747, "lat"=>41.8868076186168}]];
153:2439 Uncaught SyntaxError: Unexpected token >
Gmaps.map.create_polygons();
Gmaps.map.adjustMapToBounds();
Gmaps.map.callback();
};
window.onload = function() { Gmaps.loadMaps(); };

I passed their base tutorial (from screen cast) and markers works fine. But I had problem with polylines (as you with polygons). At the end I resolved my problem (it can help you with polygons).
So, view is the same as they gave :
<%= gmaps({
"polylines" => { "data" => #bemap_polylines }
})
%>
The model is also the same as their.
class Character < ActiveRecord::Base
belongs_to :bemap
acts_as_gmappable
def gmaps4rails_address
#describe how to retrieve the address from your model, if you use directly a db column, you can dry your code, see wiki
address
logger.info address
end
end
So, the main problem was into controller. Here is mine :
def show
#bemap = Bemap.find(params[:id])
#bemap_polylines = []
#bemap_characters = []
#bemap.characters.each do |v|
#bemap_characters << { :lng => v[:longitude], :lat => v[:latitude]}
end
#bemap_polylines << #bemap_characters
#bemap_polylines = #bemap_polylines.to_json
respond_to do |format|
format.html # show.html.erb
format.json { render json: #bemap }
end
end

Gmaps4rails doesn't provide any builtin method to create the js for polygons.
The one you use is malformed, see doc: https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Polygons.

Related

Rails API Does not split Json

Weird problem. If the class at the bottom was a module, split the Json without problems, if it was only methods, also works, but the problem is.. when it is a class, it does not split the Json anymore, and returns an empty array.. however, if being a class, I do a puts the object, it actually puts it..
Any thoughts about why? How can I fix it?
I have this controller:
def index
begin
call_employee_work_locations_api
rescue => ex
render :json => {"service unavailable": "0001" }, :status => :service_unavailable
end
end
I have this service:
def call_employee_work_locations_api
auth = {:username=>ENV["USERNAME"], :password=>ENV["PASSWORD"]}
employee_locations = HTTParty.get(employee_work_Location_url , :basic_auth => auth)
#serialize_work_location(employee_locations)
serializer = EmployeeSerializer.new
serializer.serialize_work_location(employee_locations)
end
I have this builder:
json.array!(#top_locations) do |location|
json.extract! location, :name, :description, :latitude, :longitude
end
I have this class:
class EmployeeSerializer
def serialize_work_location(employee_locations)
employee_locations= JSON.parse(employee_locations)
locations=[]
employee_locations["work_locations"].each do |attributes|
location = Location.new(attributes["latitude"],attributes["longitude"],attributes["description"],attributes["name"])
locations.push(location)
end
employee_locations_selector(locations)
end
def top_office_location_selector(locations, city)
top_locations=[]
locations.each do |office|
if office.name == city[0] then top_locations.push(office) end
if office.name == city[1] then top_locations.push(office) end
end
#top_locations = top_locations
p #top_locations <--- it prints the object perfectly, but does not pass to the view, I get an empty array instead.
end
def employee_locations_selector(locations)
city = locations.each_with_object(Hash.new(0)) { |locations, counts| counts[locations.name] += 1 }.max_by{|k,v| v}
top_office_location_selector(locations, city)
end
end
The instance variable #top_locations is being set within the scope of the EmployeeSerializer class, not your controller. As such it's just a normal instance variable and so Rails knows nothing about it. You can assign the return value of #top_office_location_selector to an instance variable in the controller and it should work.
On a side note, the code would be cleaned up a lot by using #map over #each.

Uploading multiple attachments with rails, paperclip, and angularjs

I've been stuck on this issue for a couple of days and seem to have run into a wall. I am using rails 4.1, angular 1.2.23, and paperclip 4.1. I sampled from many of the solution for similar problems but none seem to have resolved the issue.
When I set up the paperclip attachments inside of the doc model, I was able to upload a single attachment. However, when I separated the attachments from the doc model and added the images model for multiple attachments, I couldn't get it to work.
Here is the code I am using:
doc.rb
class Doc < ActiveRecord::Base
has_many :image, :dependent => :destroy
accepts_nested_attributes_for :image, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
image.rb
class Image < ActiveRecord::Base
belongs_to :doc
has_attached_file :image, :styles => { :lrg => "700x700>", :med => "350x350>", :sml => "100x100>" }, :whiny => false,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
def image=(files = [])
files.each{|f| (#image ||= []) << image.create(image: f) }
end
end
Here is my controller:
class DocsController < ApplicationController
skip_before_filter :verify_authenticity_token
def index
#docs = if params[:keywords]
Doc.where("title ilike ?", "%#{params[:keywords]}%")
else
[]
end
#items = Doc.all
end
def show
#doc = Doc.find(params[:id])
end
def create
if params[:imageData]
decode_image
#doc = Doc.new(#up)
else
#doc = Doc.new(params.require(:doc).permit(:id, :title, :parent, :info))
end
if #doc.save
render 'show', status: 201
else
render json: #doc.errors, status: :unprocessable_entity
Rails.logger.info #doc.errors
end
end
def update
doc = Doc.find(params[:id])
if params[:imageData]
decode_image
doc.update_attributes(#up)
else
doc.update_attributes(params.require(:doc).permit(:id, :title, :parent, :info))
end
head :no_content
end
def destroy
doc = Doc.find(params[:id])
doc.destroy
head :no_content
end
private
def doc_params
#up = params.require(:doc).permit(:id, :title, :parent, :info, image_attributes: [:_destroy, :id, :image])
end
def decode_image
#up = params.require(:doc).permit(:id, :title, :parent, :info, image_attributes: [:_destroy, :id, :image])
# decode base64 string
Rails.logger.info 'decoding now'
decoded_data = Base64.decode64(params[:imageData]) # json parameter set in directive scope
# create 'file' understandable by Paperclip
#data = StringIO.new(decoded_data)
#data.class_eval do
attr_accessor :content_type, :original_filename
end
# set file properties
#data.content_type = params[:imageContent] # json parameter set in directive scope
#data.original_filename = params[:imagePath] # json parameter set in directive scope
# update hash, I had to set #up to persist the hash so I can pass it for saving
# since set_params returns a new hash everytime it is called (and must be used to explicitly list which params are allowed otherwise it throws an exception)
#up[image_attributes: [:image]] = #data # image is the model attribute that is defined as an attachment using paperclip generator
end
end
Here is my upload directive using angular:
angular.module('fileUpload', []) // using restangular is optional
.directive('uploadImage', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
// listens on change event
elem.on('change', function() {
console.log('entered change function');
for (var i = 0; i < elem.length; i++) {
for (var x = 0; x < elem[i].files.length; x++) {
var file = elem[i].files[x];
// gathers file data (filename and type) to send in json
scope.doc.imageContent = file.type;
scope.doc.imagePath = file.name;
console.log(scope.doc.imagePath);
// converts file to binary string
var reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = function (e) {
// retrieves the image data from the reader.readAsBinaryString method and stores as data
// calls the uploadImage method, which does a post or put request to server
scope.doc.imageData = btoa(e.target.result);
// updates scope
}
scope.uploadImage(scope.doc.imagePath);
scope.$apply();
}
};
});
},
controller: ['$scope', '$location', '$resource', function($scope, $location, $resource){
$scope.uploadImage = function (path) {
var Doc;
Doc = $resource('/docs/:docId', {
docId: "#id",
format: 'json'
}, {
'save': {
method: 'PUT'
},
'create': {
method: 'POST'
}
});
// if updating doc
console.log($scope.doc);
var onError;
onError = function(_httpResponse) {
return flash.error = "Something went wrong";
};
if ($scope.doc.id) {
$scope.doc.$save((function() {
$scope.docImageLink = baseUrl + $scope.doc.image_url;
}), onError);
} else {
console.log("create");
}
};
}]
};
});
And finally, here is my form field:
<input type="file" id="doc.image" name="doc.image" ng-model='doc.image' upload-image multiple/>
<img ng-src="{{userImageLink}}" ng-click="openFileWindow()" ng-class="{ hidden: !userImageLink}" >
<div class="drop-box" ng-click="openFileWindow()" ng-class=" {hidden: userImageLink}">
Add Image
</div>
When I submit the form with multiple attachments, I receive this error in the rails log:
ActiveRecord::UnknownAttributeError (unknown attribute: {:image_attributes=>[:image]}):
app/controllers/docs_controller.rb:21:in `create'
This is my first major rails app so any help would be significantly appreciated. I can also provide any follow up information that is required.
Thanks!

Multiple Select Tag in Rails

Im trying to implement a multiple level drop down list in Rails
I have three Tables in my DB.
vehicle_make.rb
class VehicleMake < ActiveRecord::Base
validates_uniqueness_of :make
has_many :appointments
end
vehicle_model.rb
class VehicleModel < ActiveRecord::Base
validates_uniqueness_of :model
has_many :appointments
end
vehicle_make_model.rb
class VehicleMakeModel < ActiveRecord::Base
validates_uniqueness_of :vehicle_make_id, :scope => :vehicle_model_id
end
and im trying to implement a multiple dropdown list in appointments.html.rb
on selecting the vehicle model only corresponding make should load..
<%= f.select :vehicle_make_id, options_for_select(vehicle_make.map {|s| [s.make, s.id]}, appointment.vehicle_make_id), {}, {class: "form-control"} %>
and in my js i have..
$('#appointment_vehicle_make_id').on('change', function() {
var vehicle_make_id = this.value;
$.ajax({
url : '/appointments/update_models',
type : 'GET',
data : {
make_id : vehicle_make_id
},
success : function(response) {
console.log(response);
}
});
});
and this is my controller method.
def update_models
#vehicle_models = VehicleModel.all
#model_ids = []
#selected_vehicle_models = VehicleMakeModel.where(vehicle_make_id: params[:make_id]).order(:vehicle_model_id) unless params[:make_id].blank?
#selected_vehicle_models.each do |t|
#model_ids << t.vehicle_model_id
end
respond_to do |format|
format.html { render layout: false }
format.js
end
end
I have html page named update_models.html.erb associated to the above action.
<%= select_tag :vehicle_model_id, options_for_select(#model_ids.map {|s| [s.model, s.first.id]}, nil), {}, {class: "form-control"} %>
I get an error in terminal saying
ActionView::Template::Error (wrong number of arguments (4 for 1..3)):
1: <%= select_tag :vehicle_model_id, options_for_select(#model_ids.map {|s| [s.model, s.first.id]}, nil), {}, {class: "form-control"} %>
Im stuck here. I dont know how to proceed from here.. please help
In your controller action update_models, you are trying to render js, so it's trying to find template named as update_models.js.erb.
You can try replacing your respond_to block with:
respond_to do |format|
format.json { render :json => #model_ids }
end
Afterwards, you will need to parse this data in your ajax success callback

Undefined method `keys' for nil:NilClass error on rails

I tried to run web server and it shows the following error:
undefined method `keys' for nil:NilClass error on rails
Extracted source (around line #21):
shopsList = [st1, st2, st3, st4]
render :json => shopsList
end
end
Here are the files:
shop.rb
class Shop < ActiveRecord::Base
attr_accessor :name, :description, :comments
def initialize(name, description, comments)
#name = name
#description = description
#comments = []
end
end
comment.rb
class Comment
attr_accessor :id, :name, :content
def initialize(id, name, content)
#id = id
#name = name
#content = content
end
end
shops_controller.rb
class ShopsController < ApplicationController
def index
end
def shops
com1 = Comment.new("FX991", "Goat", "Delicious!")
com2 = Comment.new("F2888", "Cow", "Amazing!")
com3 = Comment.new("GH555", "Cat", "Yummm!")
com4 = Comment.new("HY666", "Fish", "Mouth watering!")
commentList = [com1, com2, com3, com4]
sh1 = Shop.new("AAAA", "Je", commentList[0])
sh2 = Shop.new("NNNN", "Te", commentList[1])
sh3 = Shop.new("CCCC", "Be", commentList[1])
sh4 = Shop.new("DDDD", "He", commentList[1])
shopsList = [sh1, sh2, sh3, sh4]
render :json => shopsList
end
end
When I tried changing render :json => shopsList to render :json => commentList, the comment list would show as json format in the server.
Also, is there something wrong with the way I access or declare the commentList array? The contents of the array won't show when I try to access it. It just displays "[]"
You need to pass a hash to render
try this
shopsList = [sh1, sh2, sh3, sh4]
render :json => {:success=>true, :data=>shopsList}
Can you please post the stacktrace?
I don`t think "render" is causing the error, I think it happens earlier on in the callstack.
#tested this, it is valid code
def mytest
data = ["1","2","3"]
render :json => data
end

Push name to results unless the name already exists?

I have the following in my tags controller (params[:q] comes from this plugin: http://loopj.com/jquery-tokeninput/). This is basically a slightly modified product of this screencast: http://railscasts.com/episodes/258-token-fields.
tags_controller.rb:
class TagsController < ApplicationController
def index
#tags = Tag.where("name like ?", "%#{params[:q]}%")
results = #tags.map(&:attributes)
results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}
respond_to do |format|
format.html
format.json { render :json => results }
end
end
I want to only do results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"} only if the name doesn't exist already in #tags. Because right now, it looks like this:
programming #input field
programming #drop-down menu
Add: progamming #drop-down menu
I want it to just display like
programming #input field
Add: progamming #drop-down menu
How to accomplish that?
EDIT:
Here is the model and JavaScript just in case:
application.js
$(function() {
$("#post_tag_tokens").tokenInput("/tags.json", {
crossDomain: false,
prePopulate: $("#post_tag_tokens").data("pre"),
preventDuplicates: true,
theme: "facebook"
});
});
post.rb:
def tag_tokens=(ids)
ids.gsub!(/CREATE_(.+?)_END/) do
Tag.find_or_create_by_name(:name => $1).id
end
self.tag_ids = ids.split(",")
end
You can do this:
#tag = Tag.find_by_name(params[:q])
or
#tag = Tag.name_like(params[:q]) #For this you need to install gem [searchlogic][1]
if #tag.blank?
# Do you things
end

Resources