Generate static site from JSON array - middleman

I have a giant JSON array of every US state and city, along with other data about each of them. I'd like to iterate over the JSON and output a tree structure like this:
[Alabama]
index.html
[Abbeville]
index.html
[Adamsville]
index.html
[Alaska]
index.html
[Anchorage]
index.html
[Fairbanks]
index.html
...etc
I'd have two layouts:
state.html
city.html
So far, I haven't found a great way to do this. A lot of static gens seem to have the ability to use JSON for meta data within content, but not for the primary source of content.
thanks!

The Middleman static site generator supports this. You use their dynamic pages to create a list of the pages to create. The data comes from their data file feature. Here are the links to the pages explaining these
https://middlemanapp.com/advanced/dynamic_pages/
https://middlemanapp.com/advanced/data_files/
You would do something like have states.yml containing the state and city data
- states
- name: Alabama
cities:
- name: Abbeville
pop: X
- name: Adamsville
pop: Y
and then create the proxy pages e.g.
data.states.each do |state|
proxy "/#{state.name}/index.html", "templates/state.html", :locals => {state: state}
state.cities.each do |city|
proxy "/#{state.name}/#{city.name}/index.html", "/templates/city.html", :locals => {state: state, city: city}
end
end

Related

How to prettify urls in VueJS

I have a basic SPA with VueJS front end consuming an Express api.
Currently my resource routes are like .../users/:id
However, instead of eg .../users/1,
I want .../users/sam-smith
How can I do this?
:id it is just parameter, you can change it to anything that you want, however you need to change it everywhere.
Let's say you have users like this:
[
{ id: 1, userName: 'Alice' },
{ id: 2, userName: 'Bob' }
]
And you route ...users/:id calling something like this GET ...backend/users/:id, which is probably calls something like DB.getUserById(id) - this is a great approach, because it allows to avoid collisions - e.g. all uses will devinetely have different id.
If you want to change this - you should change all the way e.g.: ...users/:userName -> ...backend/users/:userName -> DB.getUserByUserName(userName). And most important - you should make sure that all users have different user names to avoid collisions.

How to avoid rails as_json creating flood of database requests

I have a model questions that has many tags through another model question_tags. I am trying to write an api endpoint that returns a list of questions and for each question a list of it's related tag's name and id.
I'm currently using;
render json: #questions.as_json(include: {
tags: { only: %i[id name] }
})
But this runs a separate db request for every question in questions is there an alternative that will result in a smaller number of database requests?
The standard N+1 queries fixes should work here, which in Rails is eager loading.
In this case you can use include to preload the associated tags:
render json: #questions.includes(:tags).as_json(
include: {
tags: { only: %i[id name] }
}
)
You can read more about this in the dedicated rails guide section: Eager Loading Associations

Ruby on Rails: Basic parameterized queries and URL formation

I'm trying to learn how to query a rails database and return the results as JSON. In my example, I want to query the data using the parameters, city and state.
So far, in my controller, I have gotten the following action to work.
def state
#bathrooms = Bathroom.where("state = ?" ,params[:state])
respond_to do |format|
format.json { render :json => #bathrooms }
format.js { render :nothing => true }
end
end
This is also my routing entry.
match '/bathrooms/state/:state',
:controller => "bathrooms",
:action => "state"
I can call this resource with the following URL:
http://localhost:3000/bathrooms/state/CA.json
That's all good but I don't know how to query by more than one parameter. Adding and AND clause in the controller seems to be easy enough.
BUT....I don't know how to
a.) Correctly write the routing entry?
b.) What would the URL look like if I tested it in a browser?
I've tried to understand rake routes but I must be missing something.
Could someone provide a basic example for what the action should look like? What the routing entry should look like and what does the URL to access the resource look like?
Again, if written in SQL, this is what I would like to be returned.
SELECT * from bathrooms WHERE city='Chicago' AND state = 'IL'
Any help appreciated.
You don't have to pass everything by the route - the URL also support GET parameters - those are the parameters you usually see after the question mark in the URL. You can add those GET parameters without changing your routes: http://localhost:3000/bathrooms/state/IL.json?city=Chicago. Then your can access the city parameter via params[:city]. but in your case, I think it will be better to use http://localhost:3000/bathrooms/index.json?state=IL&city=Chicago. You'll also need to change your routing to
match '/bathrooms/index',
:controller=>:bathrooms,
:action=>:index
and put the code in the index method of BathroomsController. You access the parameters the same - but the concept is different - you don't enter a state and look for bathrooms by city, you just look for bathrooms by state and city.
Anyways, you don't want to write the URL by hand - you want to a Rails helper or an HTML form generate it:
link_to "bathroom in Chicago, IL",:controller=>:bathrooms,:action=>:index,:state=>'IL',:city=>'Chicago'
If you want to use a form(to let the users choose their own state and city), you need to set it's method to GET:
form_tag {:controller=>:bathrooms,:action=>:index},:method=>:get do
and put state and city as fields.
It's also worth noting that while you can use SQL's AND to perform a search by multiple fields, you can also chain where methods: Bathroom.where(:state=>params[:state]).where(:city=>params[:city]).
You can put any arbitrary parameters in your querystring.
For example:
http://localhost:3000/bathrooms/state/CA.json?city=Chicago
your query looks like this:
#bathrooms = Bathroom.where("state = ? and city= ?" ,params[:state], params[:city])

Once a store is registered, automatically creating a landmark on Google Maps

I am trying to have a store register with their address, which once registered will automatically create a landmark on google maps of the location. How should I go about doing this? I have been using Ruby on Rails for the majority on
Geokit is fairly easy to implement. If you are just beginning to use the Google mapping API, I would recommend starting here: https://github.com/jlecour/geokit-rails3.
Once you get it setup properly, you can do something like this in your controller...
#event = Event.find(params[:id])
if #event.is_geocoded?
#map = GMap.new("map_div", 'map')
#map.control_init(:large_map => true, :map_type => false)
#map.center_zoom_init(#event.latlon,12)
#map.overlay_init(GMarker.new(#event.latlon, :title => #event.name, :info_window => #event.address_for_map_popup))
end
In your view, something like this:
- if #map
- initialize_map
= #map.to_html.html_safe
= #map.div(:width => 478, :height => 400).html_safe
It is the GMarker that creates the map marker and overlay_init that overlays it on top of the map.
So the best way would probably be to store their location in a database (or translate to coordinates first then store in database). From there you can use something like google maps javascript api to drop pins onto a map you generate.
http://code.google.com/apis/maps/documentation/javascript/

What is the proper RESTful way to "like" something in Rails 3?

Let's say I have a Rails 3 app that displays videos. The user can "Like" or "Dislike" the videos. Also, they can like/dislike other things like games. I need some help in the overall design and how to handle the RESTful routes.
Currently, I have a Like Class that uses polymorphic design so that objects are "likeable" (likeable_id, likeable_type)
I want to do this via AJAX (jQuery 1.5). So I was thinking something like:
javascript
// these are toggle buttons
$("likeVideo").click( function() {
$.ajax({
url: "/likes/video/" + video_id,
method: "POST",
....
});
} );
$("likeGame").click( function() {
$.ajax({
url: "/likes/game/" + game_id,
method: "POST",
....
});
} );
rails controller
Class Likes < ApplicationController
def video
# so that if you liked it before, you now DON'T LIKE it so change to -1
# or if you DIDN'T like it before, you now LIKE IT so change to 1
# do a "find_or_create_by..." and return JSON
# the JSON returned will notify JS if you now like or dislike so that the
# button can be changed to match
end
def game
# same logic as above
end
end
Routes
match "/likes/video/:id" => "likes#video", :as => :likes_video
match "/likes/game/:id" => "likes#game", :as => :likes_game
Does this logic seem correct? I am doing a POST via AJAX. Technically, shouldn't I be doing a PUT? Or am I being too picky over that?
Also, my controller uses non-standard verbs. Like video and game. Should I worry about that? Sometimes I get confused on how to match up the "correct" verbs.
An alternative would be to post to something like /likes/:id with a data structure that contains the type (game or video). Then I could wrap that in one verb in the controller...maybe even Update (PUT).
Any suggestions would be appreciated.
Rest architectural style does not specify which "verb" you should be using for what. It simply says that one can use HTTP if they want to for connectors.
What you are looking for is HTTP specifications for method definitions. In particular POST is intended for:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
while PUT:
requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.
Which category your functionality falls into is up to you - as long as you are consistent with yourself about it.