Skip to content

Instantly share code, notes, and snippets.

@TheMetalCode
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheMetalCode/7595d9740b389bb59595 to your computer and use it in GitHub Desktop.
Save TheMetalCode/7595d9740b389bb59595 to your computer and use it in GitHub Desktop.

Attempt to simplify and convert tagmap to Rails

http://tag-map.herokuapp.com/map

Instagram photos tagged with #rubyonrails in Chicago, Illinois.

QUESTIONS

  • What type of response will we be getting from instagram-ruby-gem and how to process it?
  • How to integrate all of this with leaflet-rails?
  • How do tile layers and mapbox.js fit into all of this, and will we end up having to pay for their services?

Attempted conversion to Rails

main.rb

# encoding: utf-8

require 'instagram'
require 'hashie'

Image = Struct.new(:latitude, :longitude, :thumbnail, :url)

class Instagram
  
  # Chicago, Illinois

  LATITUDE = "41.8819"
  LONGITUDE = "87.6278"
  RADIUS_IN_METERS = "5000"
  
  client = Instagram::Client.new(
    client_id: "4f6b2bf5ebc441c282d2db4949de66b3",
    client_secret: "591cf96a26924741b721a7c80e4ffefe",
    format: 'json'
  )
  
  def self.fetch tag
    
    # https://github.com/Instagram/instagram-ruby-gem
    
    response = client.tag_recent_media(tag)
    # response = client.location_search(LATITUDE, LONGITUDE, RADIUS_IN_METERS)
    
    # Not sure if the below is needed:
    
    # https://github.com/intridea/hashie#deepfetch

    mash.extend Hashie::Extensions::DeepFetch

    hashes = JSON.parse(response)
    mashes = Hashie::Mash.new(hashes)
    
    images = []
 
    mashes.images.each do |mash|
      image = Image.new

      image.latitude = mash.deep_fetch(:lorem)
      image.longitude = mash.deep_fetch(:ipsum)
      image.thumbnail = mash.deep_fetch(:dolor)
      image.url = mash.deep_fetch(:sit)
    end
  end
end

main_controller.rb

#Only the ApplicationController inherits from ActionController::Base, all other controllers inherit from ApplicationController
class MainController < ApplicationController
  def index
    #Instagram is the class that actually has the .fetch
    @images = Instagram.fetch '#rubyonrails'
  end
end

index.html.erb

<h1>Ruby on Rails in Chicago</h1>
<p>Instagram photos tagged with `#rubyonrails` in Chicago, Illinois.</p>
<div id="map">

  <!-- https://github.com/axyjo/leaflet-rails -->
  
  <!-- https://mapbox.com/mapbox.js/api/v2.0.1/ -->
  
  <!-- So here's how I use the leaflet-rails view helper -->  
  
  <%= map(center: { latlng: [lat, lng], zoom: 13}, markers: [{latlng: [lat, lng], popup: 'Some text you want to pop up on hover', icon: ICON_OPTIONS}]) %>
  
  <!-- Icon options are for using your own custom marker icons -->
  ICON_OPTIONS = {name: 'my custom icon', icon_url: 'path/to/image', shadow_url: 'path/to/shadow-image'}
  
  <%= map(:center => {
    mapbox.accessToken: 'pk.eyJ1IjoiZnJhbmtvIiwiYSI6ImhM',
    latlng: ["41.8819", "87.6278"]
  }) %>
    
  <% images.each do |image| %>
    <%= image.thumbnail, image.url %>
  <% end %>
</div>

leaflet.rb

# Having just signed up for Mapbox, what should I add here?
 
Leaflet.tile_layer = "http://{s}.tile.cloudmade.com/YOUR-CLOUDMADE-API-KEY/997/256/{z}/{x}/{y}.png"

# I just use a new Mapbox project here and do the tile_layer this way

Leaflet.tile_layer = 'http://{s}.tiles.mapbox.com/v3/YOUR_MAPBOX_PROJECT_MAP_ID/{z}/{x}/{y}.png'
Leaflet.attribution = 'some text you want on the map other than Leflet text'
Leaflet.max_zoom = 18

Gemfile

gem 'instagram'
gem 'leaflet-rails'
gem 'hashie'

source 'https://rails-assets.org'

gem 'rails-assets-mapbox.js'

application.js

//= require leaflet
//= require mapbox

application.css

*= require leaflet
*= require mapbox

Original Sinatra files

server.rb

require 'sinatra'
require 'instagram'
require 'mongo_mapper'
require 'active_support'
require 'redis'

class Image
  include MongoMapper::Document

  key :location, Hash
  key :images, Hash
  key :user, Hash
  key :data, Hash
  
  timestamps!

end

$redis = Redis.new(:url => ENV['REDISTOGO_URL'])

configure do
  MongoMapper.setup({'production' => {'uri' => ENV['MONGOHQ_URL']}}, 'production')
end

Instagram.configure do |config|
  config.client_id = ENV['INSTAGRAM_CLIENT_ID']
  config.client_secret = ENV['INSTAGRAM_CLIENT_SECRET']
end

configure :production do
  require 'newrelic_rpm'
end

get '/' do
  'Hi!'
end

get '/map' do
  erb :map, :locals => { :images => Image.all, :min_tag_id => $redis.get('min_tag_id') }
end

# Verifies subscription (http://instagram.com/developer/realtime/)
get '/callback' do
  request['hub.challenge'] if request['hub.verify_token'] == ENV['HUB_TOKEN']
end

# Receive subscription (http://instagram.com/developer/realtime/)
post '/callback' do
  begin
    process_subscription(request.body.read, env['HTTP_X_HUB_SIGNATURE'])
  rescue Instagram::InvalidSignature
    halt 403
  end
end

# Do magic...
def process_subscription(body, signature)
  fail Instagram::InvalidSignature unless signature

  Instagram.process_subscription(body, signature: signature) do |handler|
    handler.on_tag_changed do |tag_id, _|
      return if tag_id != ENV['TAG']
      min_tag_id = $redis.get 'min_tag_id'
      
      if min_tag_id
        medias = Instagram.tag_recent_media(tag_id, 'min_tag_id' => min_tag_id)
      else
        medias = Instagram.tag_recent_media(tag_id)
      end
      
      min_tag_id = medias.pagination[:min_tag_id]
      $redis.set('min_tag_id', min_tag_id) if min_tag_id
      medias.each do |media|
        next unless media.location
        Image.create(:data => media, :location => media.location, :images => media.images, :user => media.user)
      end
    end
  end
  "Done" # FIXME Need to return something otherwise Sinatra barfs
end

map.rb

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />

    <title>Tag Map</title>

    <!-- Bootstrap core CSS -->
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
    
    <style>
    /* Sticky footer styles
    -------------------------------------------------- */
    html {
      position: relative;
      min-height: 100%;
    }
    body {
      /* Margin bottom by footer height */
      margin-bottom: 60px;
    }
    
    #footer {
      position: absolute;
      bottom: 0;
      width: 100%;
      /* Set the fixed height of the footer here */
      height: 60px;
      background-color: #f5f5f5;
    }
    
    #map { height: 580px; }
    
    .title {
      font-size: 11px;
      line-height: 15px;
      font-weight: bolder;
      color: blueviolet;
    }

    p.caption {
      font-size: 11px;
      line-height: 15px;
      width: 150px;
      margin: 0px;
      padding: 5px 0px;
    }
    
    .container {
      width: auto;
      max-width: 880px;
      padding: 0 15px;
    }
    .container .text-muted {
      margin: 20px 0;
    }
    
    a.actions{
      float: right;
      text-decoration: none;
    }
    
    </style>
  </head>

  <body>
    <!-- Begin page content -->
    <div class="container">
      <div class="page-header">
        <h1>Tag Map</h1>
      </div>

      <p class="lead">Tag an Instagram photo with #mikva and and location and it should show up here.</p>
      
      <div id="map"></div>
      
      <script>
        var map = L.map('map').setView([41.88, -87.65], 12);
        L.tileLayer('http://{s}.tiles.mapbox.com/v3/arfon.ii8k0h60/{z}/{x}/{y}.png', {
                      attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
                      maxZoom: 18
        }).addTo(map);
        
        <% images.each do |image| %>
        <% if image.location %>
          var marker = L.marker([<%= image.location['latitude'] %>, <%= image.location['longitude'] %>]).addTo(map);
          marker.bindPopup("<a href='<%= image.data['link'] %>' %><img src=<%= image.images['thumbnail']['url'] %> height='150px' width='150px'></a>");
        <% end %>


        <% end %>
      </script>
    </div>


    <div id="footer">
      <div class="container">
        <p class="text-muted">Tag Map &middot; <a href="https://github.com/arfon/tagmap">GitHub</a> &middot; <%= min_tag_id %></p>
      </div>
    </div>
  </body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment