Trying to combine Users into the same marker using gmaps4rails - ruby-on-rails

I can't figure out how to combine users into the same markers in gmaps4rails. I feel like I'm somewhat close, but can't exactly figure out what I'm doing wrong between using the gmaps4rails helper, converting to JSON, and rendering by partial.
def map
distinct_locations = User.where("location IS NOT NULL").select("DISTINCT(LOCATION)").map(&:location)
#markers = []
distinct_locations.each do |city|
temp_marker = User.where(:location => city).first.to_gmaps4rails
city_users = User.where(:location => city)
render_to_string(:partial => "/users/map_marker_info", :locals => { :users => city_users})
#markers << temp_marker
end
#markers
end
As you can see, in my controller, I first get an array of distinct_locations, which is just an array of city names (like "New York, New York").
Then I create the #markers to hold the JSON I'll eventually return.
For each unique city that I found, I'm TRYING to first create a marker using the to_gmaps4rails helper using the first User I find in that city. Then I'm trying to find all the other users in the city (via city_users = User.where(:location => city).
I'm then trying to render my partial using this collection of Users in the same city with something like this for now (but eventually will pull different attributes from Users):
#_map_marker_info.html.haml
.map_info_window
%h4
=users.first.location
%p
=users.count
Finally, I add the marker to #markers after each city is processed.
Eventually, I return #markers as a JSON that then becomes a beautiful map thanks to the awesome gmaps4rails gem.
I'm sure I'm doing a lot of things wrong (and probably many things inefficiently)...but can someone help me just to get it working?

Well, just one of those moments when things crystallize after you post a question. Anyways, here's what I have and it works. (Though still open to people giving more efficient answers). This "custom marker" is very very similar to the official documentation:
https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Controller
def map
#markers = User.select("DISTINCT ON (location) *").where("location IS NOT NULL").all.to_gmaps4rails do |user, marker|
city_users = User.where(:location => user.location)
marker.infowindow render_to_string(:partial => "/users/map_marker_info", :locals => { :users => city_users })
end
end
Basically, select Users based on distinct locations (you really only need the latitude and longitude columns for the to_gmaps4rails helper to work. Also I removed the nil values for people who don't have locations.
Then for each "location", essentially, create the marker, but for the locals, pass in all the Users with the same location. That's what city_users is for -- all the users in the same city.
And so now I can do something like this in my partial:
.map_info_window
%h4
=users.count
in
=users.first.location
-users.each do |user|
=link_to user.full_name, user

Related

Rails 3, change or fill submitted form values in controller

I have two independent "component" models, contacts and articles. Contacts come in many types (producers, exporters etc...).
In the new article form I have a dropdown selector with contacts (id and title) and want to store the selected value and text in the article table.
In the new article form view:
<%= f.select :producer_id, options_for_select(producers, #article.producer_id) %>
That works and producer_id is stored in article table.
That's clear and logical to me, but in some cases I also need to store the selected contact's title in producer_title.
I have read many different options like "do it in model, before save", or "do it in controller", and I have done it inside controller.
Article controller (only part from update):
#cont_name is producer title from Contacts
def update
params[:article][:producer_title] = Contact.where(id: params[:article][:producer_id]).pluck(:cont_name).first
end
This works, but is it the best-practices approach to this problem?
Also, why I can't get it to work if I change the params[producer_id] part to use: id: params[:producer_id] ?
Best regards and thanks.
How about something like the following instead:
def edit
#article = Article.find(params[:id])
#producers = Contact.where(type: "producer") # or however you distinguish between producers and other contacts
end
Then in your form change it to:
f.select :producer_id, options_from_collection_for_select(#producers, "cont_name")
# you might need to do (#producers, "cont_name", "cont_name"), can't quite remember
Then your update action will be much simpler:
def update
#article = Article.find(params[:id])
if #article.update_attributes(params[:article])
...
else
...
end
end
The reason :id => params[:producer_id] doesn't work is that params is a nested hash, so something like:
params = { :article => { :producer_id => 34, :title => "Cool Article" }, :another_key => { :key => :value } }
So to access the producer_id you first have to retrieve the article hash, otherwise it will only look through the first set of keys which include article and another_key in the example above, but don't include producer_id.

Not able to render partial with Gmaps4Rails

I have a map which has got marker based on state of US. Each state has n number of city.
I have got a state model, controller and city model, controller.
When I click on the marker of the state, I want the list of cities to be displayed in the info window.
All this information is appearing on the homepage.
This is what I have done so far :-
home_controller.rb
def index
#states = State.all.to_gmaps4rails do |state,marker|
marker.infowindow render_to_string(:partial => "/states/gmaps4rails_infowindow", :locals => {:object => state})
marker.json({:id => state.id})
end
end
home/index.html.haml
=gmaps({"map_options" =>{ "auto_zoom" => false, "zoom" => 3}, "markers" => { "data" => #states } })
state_controller.rb
def gmaps4rails_infowindow
#state = Gmaps.map.markers
end
states/_gmaps4rails_infowindow.html.haml
=#state.cities.each do |city|
=city.name
Needless to say that it is not working. Can someone please help me out?
Well, your home_controller.rb is fine. you write here you want to use a partial with a local variable named object.
In the partial itself, you write:
=#state.cities.each do |city|
=city.name
The instance variable isn't defined there, you defined a local variable just above.
Replace with:
=object.cities.each do |city|
=city.name
From there it should work.
Notice:
def gmaps4rails_infowindow
#state = Gmaps.map.markers
end
is:
useless: you define the infowindow in the controller
wrong: Gmaps.map.markers only lives as js variable

Rails Craiglist like list of items

So I have a state model and city model associated with has_many and belongs_to. I want to display a page with each state with its associated cities underneath.
I created a page controller and page called "Locations" and manually entered in
<%= link_to "Allentown", allentown_path %>
which then takes you to the allentown page.
On the allentown page I filtered the listings by adding this code to the pages controller
def allentown
#title = "Allentown Listings"
#tattoo_briefs = TattooBrief.where( :city_id => 1 ).find(:all, :order => "id DESC" )
end
I know this isn't DRY. Also can get very cumberson if I have 200 cities. Is there a better way?
You need to add a resource to your routes:
routes.rb
resources :city
That essentially gives you all the RESTful actions for the City model. Then, in your controller, use the show action to..wait for it..show your city page
cities_controller.rb
def show
#city = City.find(params[:id])
#title = "#{#city.name} Listings"
#tattoo_briefs = TattooBrief.where( :city_id => params[:id] ).find(:all, :order => "id DESC" )
end
you can still modify this by studying more on routes and controllers from the rails api. With added knowledge, you can get to allentown by modifying your route to use the city name instead of the id.

Rails/ajax - whitespace and request.raw_post

I am starting to learn Ajax with rails.
I have a catalog index page with a text_field_tag querying db if it finds similar "section" results.
Index.html.erb
<h1>Catalogs</h1>
<label>Search by Section:</label>
<%=text_field_tag :section %>
<%= observe_field(:section,
:frequency=> 0.1,
:update=> "article_list",
:url=>{ :action => :get_article_list }) %>
<div id="article_list"></div>
Catalogs_controller.rb
def index
end
def get_article_list
#section = request.raw_post.split(/&/).first
#catalogList = "<ol>"
Catalog.find(:all, :conditions => ["section = ?", #section]).each do |catalog|
#catalogList += "<li>" + catalog.title + "</li>"
end
#catalogList += "</ol>"
render :text => #catalogList
end
Question:
request.raw_post renders something like:
xml&authenticity_token=tgtxV3knlPvrJqT9qazs4BIcKYeFy2hGDIrQxVUTvFM%3D
so I use
request.raw_post.split(/&/).first
to get the section query ("xml"). It works, however how can I do if the query have a whitespace. (like "Open Source") In fact, I have Open Source sections in my db, but request.raw_post.split(/&/).first renders Open%20Source. How can I manage this? Did I have to use a full text search engine to achieve it or there is another way?
Thanks a lot for your explanation!
Look over your logs, in them you will see the post and the params being passed. You should not need to do your own query-string splitting. You should be able to use params[:section] to get the post data.
As your comment implies, there's something missing. Your observe_field needs to tell the Rails helper what to do. Check out: http://apidock.com/rails/ActionView/Helpers/PrototypeHelper/observe_field. Anyhow, you'll want to do something like:
observe_field(... # lots of parameters
:with => 'section'
)
And that should give you params[:section].

Using sortable_element in Rails on a list generated by a find()

I'm trying to use the scriptaculous helper method sortable_element to implement a drag-and-drop sortable list in my Rails application. While the code for the view looks pretty simple, I'm really not quite sure what to write in the controller to update the "position" column.
Here's what I've got in my view, "_show_related_pgs.erb":
<ul id = "interest_<%=#related_interest.id.to_s%>_siblings_list">
<%= render :partial => "/interests/peer_group_map", :collection => #maps, :as => :related_pg %>
</ul>
<%= sortable_element("interest_"+#related_interest.id.to_s+"_siblings_list", :url => {:action => :resort_related_pgs}, :handle => "drag" ) %>
<br/>
And here's the relevant line from the partial, "interests/peer_group_map.erb"
<li class = "interest_<%=#related_interest.id.to_s%>_siblings_list"
id = "interest_<%=related_pg.interest_id.to_s%>_siblings_list_<%=related_pg.id.to_s%>">
The Scriptaculous UI magic works fine with these, but I am unsure as to how to change the "position" column in the db to reflect this. Should I be passing the collection #maps back to the controller and tell it to iterate through that and increment/decrement the attribute "position" in each? If so, how can I tell which item was moved up, and which down? I couldn't find anything specific using Chrome dev-tools in the generated html.
After each reordering, I also need to re-render the collection #maps since the position is being printed out next to the name of each interest (I'm using it as the "handle" specified in my call to sortable_element() above) - though this should be trivial.
Any thoughts?
Thanks,
-e
I typically create a sort action in my controller that looks like this:
def sort
order = params[:my_ordered_set]
MyModel.order(order)
render :nothing => true
end
Don't forget to add a route:
map.resources :my_model, :collection => { :sort => :put }
Now, on MyModel I add a class method that updates all of the sorted records with one query (this only works in mysql, I think..):
def self.order(ids)
update_all(
['ordinal = FIND_IN_SET(id, ?)', ids.join(',')],
{ :id => ids }
)
end
The single query method comes from Henrik Nyh.

Resources