Geocoding multiple addresses in one model - ruby-on-rails

I am trying to geocode 2 addresses in a model using geocoder and I can't get gem to work as I want to. Here is the code that I am applying to my model:
class Sender < ActiveRecord::Base
validates_presence_of :source_address
validates_presence_of :destination_address
geocoded_by :source_address, :latitude => :latitude1, :longitude => :longitude1
geocoded_by :destination_address, :latitude2 => :latitude2, :longitude2 => :longitude2
def update_coordinates
geocode
[latitude1, longitude1, latitude2, longitude2]
end
after_validation :geocode
Here is code for views/senders/show.html.erb:
<%= #sender.latitude1 %>
<%= #sender.longitude1 %>
<%= #sender.latitude2 %>
<%= #sender.longitude2 %>
Result : 35.6894875 139.6917064 - Isn't it supposed to send me back 2 address information?
Here is my js:
<script type="text/javascript">
function initialize() {
var source = new google.maps.LatLng(<%= #sender.latitude1 %>, <%= #sender.longitude1 %>);
var dest = new google.maps.LatLng(<%= #sender.latitude2 %>, <%= #sender.longitude2 %>);
var mapOptions = {
center: source,
zoom: 8
}
var mapOptions2 = {
center: dest,
zoom: 8
}
var map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var map2 = new google.maps.Map(document.getElementById('map_canvas2'), mapOptions2);
var marker = new google.maps.Marker({
position:source,
map: map
});
var marker2 = new google.maps.Marker({
position:dest,
map: map2
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>

The problem and solution are mentioned here.
Add the following before_save and corresponding method to your model to solve the problem. Don't forget to repeat the part of code for the second location (maybe destination):
before_save :geocode_endpoints
private
#To enable Geocoder to works with multiple locations
def geocode_endpoints
if from_changed?
geocoded = Geocoder.search(loc1).first
if geocoded
self.latitude = geocoded.latitude
self.longitude = geocoded.longitude
end
end
# Repeat for destination
if to_changed?
geocoded = Geocoder.search(loc2).first
if geocoded
self.latitude2 = geocoded.latitude
self.longitude2 = geocoded.longitude
end
end
end

Rewrite
def function
...
end
as:
def update_coordinates
geocode
[latitude, longitude, latitude2, longitude2]
end
And also:
geocoded_by :destination_address, :latitude => :latitude2, :longitude => :longitude2
You also don't need :latitude => :lat, :longitude => :lon here:
geocoded_by :source_address, ...
And finally, coordinates are fetched automatically after record is validated. So you could do without update_coordinates (or function, in your version) and arrange the view for show action like this:
<%= #sender.latitude %>
<%= #sender.longitude %>
<%= #sender.latitude2 %>
<%= #sender.longitude2 %>

Related

Trouble Creating Rails Stripe Subscription

New-ish Ruby Rails programmer here, please help me learn. I am having a difficult time creating a subscription in Stripe. It is an app where schools will be registering to. I already created a plan in Stripe with an ID called, 'reach' and I am able to create a Stripe Customer Token, but not a Subscription.
On my registration form (in views), I have a hidden_field_tag with the plan name as 'reach' which is passed through the URL, params. I also have a hidden field in the form of the stripeToken.
I have a class called SchoolRegistration and the code underneath is here:
attr_accessor :stripeToken
attr_accessor :plan
def save_with_subscription
if valid?
customer = Stripe::Customer.create(description: email, plan: plan, source: stripeToken)
self.stripe_customer_token = customer.id
save!
end
end
What I discovered recently is the <%= hidden_field_tag :plan, params[:plan] %> in my views is NOT saving to my database. I can see it on my console when I hit submit, but it never gets saved to the database. How can I save that in the database?
Controller:
class SchoolRegistrationsController < ApplicationController
def new
#register = SchoolRegistration.new
end
def create
#register = SchoolRegistration.new(register_params)
if #register.save_with_subscription
flash[:success] = "Congratulations! You have registered your school!
redirect_to new_user_registration_path
else
flash[:danger] = #register.errors.full_messages.join(", ")
redirect_to new_registration_path
end
end
private
def register_params
params.require(:school_registration).permit(:name_of_person_completing_form, :email, :role_in_school, :school_name, :grade_levels, :street_name, :city, :state, :zip_code)
end
end
params.require is indented in my code...not sure why it wouldn't indent here.
JavaScript:
/* global $ Stripe */
//Document ready.
$(document).on('turbolinks:load', function(){
//Set Stripe public key.
var stripe = Stripe($('meta[name="stripe-key"]').attr('content'));
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '16px',
color: "#32325d",
}
};
// Create an instance of the card Element
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>
card.mount('#card-element');
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server
stripeTokenHandler(result.token);
}
});
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
I know it is probably obvious, I am just having a difficult time and I did check out the documentation. Please help me learn and much thanks to all of you! Let me know if you need more info or code - using Rails 5.
create the subscription by associating the plan with the customer id witch you get when creating customer on stripe
Stripe::Subscription.create(
:customer => "cus_4fdAW5ftNQow1a",
:items => [
{
:plan => "basic-monthly",
},
],
)
For more information https://stripe.com/docs/subscriptions/quickstart
Ok, I'm trying to give a full stripe implementation solution, you follow this step by step, all code is tested and go to the live site for testing here the site
This example only Stripe payment
Add this on view/layouts/application.html.erb
<%= javascript_include_tag "https://js.stripe.com/v2/" %>
just above
<%= javascript_include_tag "application" %>
Create environment variable with Stripe keys
STRIPE_TEST_PUBLISHABLE_KEY: pk_test_xxxxxxxxxx
STRIPE_TEST_SECRET_KEY: sk_test_xxxxxxxxxxxxx
On the registration file, add the code below to the top of the file:
<script language="Javascript">
Stripe.setPublishableKey("<%= ENV['STRIPE_TEST_PUBLISHABLE_KEY'] %>");
</script>
And add this class on your form cc_form
Create a model for payment with references
rails g model Payment email:string token:string school_registration:references
Will generate a file under db like belo
class CreatePayments < ActiveRecord::Migration[5.0]
def change
create_table :payments do |t|
t.string :email
t.string :token
t.references :school_registration, foreign_key: true
t.timestamps
end
end
end
Then
rake db:migrate
#=> model/SchoolRegistration.rb
#=> add these two lines
has_one :payment
accepts_nested_attributes_for :payment
On the payment.rb
attr_accessor :card_number, :card_cvv, :card_expires_month, :card_expires_year
belongs_to :school_registration
def self.month_options
Date::MONTHNAMES.compact.each_with_index.map { |name, i| ["#{i+1} - #{name}", i+1]}
end
def self.year_options
(Date.today.year..(Date.today.year+10)).to_a
end
def process_payment
customer = Stripe::Customer.create email: email, card: token
Stripe::Charge.create customer: customer.id, amount: 1000, description: 'Premium', currency: 'usd'
#=> 1000 means 1000 cents that means 10 dollars
end
Now on your form
<%= fields_for( :payment ) do |p| %>
<div class="row col-md-12">
<div class="form-group col-md-4 no-left-padding">
<%= p.label :card_number, "Card Number", data: {stripe: "label"} %>
<%= p.text_field :card_number, class: "form-control", required: true, data: {stripe: 'number'} %>
</div>
<div class="form-group col-md-2">
<%= p.label :card_cvv, "Card CVV", data: {stripe: "label"} %>
<%= p.text_field :card_cvv, class: "form-control", required: true, data: {stripe: 'cvv'} %>
</div>
<div class="form-group col-md-6">
<div class="col-md-12">
<%= p.label :card_expires, "Caed Expires", data: {stripe: "label" } %>
</div>
<div class="col-md-3">
<%= p.select :card_expires_month, options_for_select(Payment.month_options),
{ include_blank: 'Month' },
"data-stripe" => "exp-month",
class: "form-control", required: true %>
</div>
<div class="col-md-3">
<%= p.select :card_expires_year, options_for_select(Payment.year_options.push),
{ include_blank: 'Year' },
class: "form-control",
data: { stripe: "exp-year" }, required: true %>
</div>
</div>
</div>
<% end %>
And now create JS file under javascripts folder named like stripe.js
$(document).ready(function() {
var show_error, stripeResponseHandler, submitHandler;
submitHandler = function (event) {
var $form = $(event.target);
$form.find("input[type=submit]").prop("disabled", true);
//If Stripe was initialized correctly this will create a token using the credit card info
if(Stripe){
Stripe.card.createToken($form, stripeResponseHandler);
} else {
show_error("Failed to load credit card processing functionality. Please reload this page in your browser.")
}
return false;
};
$(".cc_form").on('submit', submitHandler);
stripeResponseHandler = function (status, response) {
var token, $form;
$form = $('.cc_form');
if (response.error) {
console.log(response.error.message);
show_error(response.error.message);
$form.find("input[type=submit]").prop("disabled", false);
} else {
token = response.id;
$form.append($("<input type=\"hidden\" name=\"payment[token]\" />").val(token));
$("[data-stripe=number]").remove();
$("[data-stripe=cvv]").remove();
$("[data-stripe=exp-year]").remove();
$("[data-stripe=exp-month]").remove();
$("[data-stripe=label]").remove();
$form.get(0).submit();
}
return false;
};
show_error = function (message) {
if($("#flash-messages").size() < 1){
$('div.container.main div:first').prepend("<div id='flash-messages'></div>")
}
$("#flash-messages").html('<div class="alert alert-warning"><a class="close" data-dismiss="alert">×</a><div id="flash_alert">' + message + '</div></div>');
$('.alert').delay(5000).fadeOut(3000);
return false;
};
});
And finally, go to controller and add those lines
if #register.save
#payment = Payment.new({email: params["school_registration"]["email"],
token: params[:payment]["token"], school_registration_id: #register.id
})
flash[:error] = "Please check registration errors" unless #payment.valid?
begin
#payment.process_payment
#payment.save
rescue Exception => e
flash[:error] = e.message
#register.destroy
render :new and return #=> :new means your registration form
end
else
#=> Code
end
This is actually one-time subscription and Stripe basic implementation if you implement this carefully and succeed you can whatever which you need.
And for more go to Rails Checkout Guide
Hope to help

Iterate through array of arrays and pass coordinates to google map

In my Rails app I have google map that I want to display pins based on coordinates (latitude, longitude). I have dummy data in user.rb file as an array and I'm trying to map through it and pass coordinates to google map, however I'm missing something basic, because all works if I supply it manually. So how do I iterate so coordinates would be displayed on map?
#user.rb
class User < ApplicationRecord
COORDINATES = [[51.50853, -0.076132], [51.510357, -0.116773]]
def self.latitude
COORDINATES.map do |x|
x[0] # How to pass coordinates correctly?
end
end
def self.longitude
COORDINATES.map do |x|
x[-1] # How to pass coordinates correctly?
end
end
end
That's User controller index action:
def index
#latitude = User.latitude
#longitude = User.longitude
end
And that's index.html.erb. Here I provide #latitude and #longitude.
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers([
{
"lat": <%= #latitude %>,
"lng": <%= #longitude %>
}
]);
});
try this:
markers = handler.addMarkers([
<% User::COORDINATES.each.with_index do |geo,i| %>
{
"lat": <%= geo[0] %>,
"lng": <%= geo[1] %>
}
<% if User::COORDINATES[i+1] %>,<% end %>
<% end %>
]);

Rails: Gmaps4Rails & Geocoder - setup

Trying to figure out how to display a map in my rails 4 app show page.
I have a model called addresses. This is the address.rb file:
class Address < ActiveRecord::Base
geocoded_by :full_address # can also be an IP address
before_save :capitalise_address
before_save :upcase_zip
# --------------- associations
belongs_to :addressable, :polymorphic => true
# --------------- scopes
# --------------- validations
validates_presence_of :unit, :street, :zip, :country
# --------------- class methods
def first_line
[unit, street].join(' ')
end
def middle_line
if self.building.present?
end
end
def last_line
[city, region, zip].join(' ')
end
def country_name
self.country = ISO3166::Country[country]
country.translations[I18n.locale.to_s] || country.name
end
def address_without_country
[self.first_line, middle_line, last_line].compact.join(" ")
end
def full_address
[self.first_line, middle_line, last_line, country_name.upcase].compact.join("\n")
end
# --------------- callbacks
# after_validation :geocode, if self.full_address.changed?
# --------------- instance methods
# --------------- private methods
protected
def upcase_zip
zip.upcase
end
def capitalise_address
["building", "street", "city", "region", "country" ].each do | name |
self.attributes[name] = self.attributes[name].capitalize
end
end
end
I have added geocoded, gmap4rails, underscore gems to my gem file.
In my addresses controller I have:
class AddressesController < ApplicationController
before_action :set_address, only: [:show, :edit, :update, :destroy]
respond_to :html, :xml, :json
def index
#addresses = Address.all
respond_with(#addresses)
end
def show
respond_with(#address)
end
def new
#address = Address.new
respond_with(#address)
end
def edit
end
def create
#address = Address.new(address_params)
#address.save
respond_with(#address)
end
def update
#address.update(address_params)
respond_with(#address)
end
def destroy
#address.destroy
respond_with(#address)
end
private
def set_address
#address = Address.find(params[:id])
end
def address_params
params[:address].permit(:unit, :building, :street, :city, :region, :zip, :country)
end
end
In my address show page I have:
<script src="//maps.google.com/maps/api/js?v=3.13&sensor=false&libraries=geometry" type="text/javascript"></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js" type="text/javascript"></script>
<div class="containerfluid">
<div class="row">
<div class="col-md-12">
<div style='width: 800px;'>
<div id="map" style='width: 800px; height: 400px;'>
</div>
</div>
<div class="addressbacking">
<%= #address.full_address %>
<div style='width: 800px;'>
<div id="one_marker" style='width: 800px; height: 400px; z-index:1'></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw #hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
</script>
I am trying to follow this set up tutorial, which suggests adding this to my controller:
def index
#users = User.all
#hash = Gmaps4rails.build_markers(#users) do |user, marker|
marker.lat user.latitude
marker.lng user.longitude
marker.title user.title
end
end
Which I do (although I don't know what it means or if its the cause of my problem), so that my index action in the controller is:
def index
#addresses = Address.all
respond_with(#addresses)
#hash = Gmaps4rails.build_markers(#users) do |user, marker|
marker.lat user.latitude
marker.lng user.longitude
marker.title user.title
end
end
I have a form partial in my views which has input elements for each of the strong params showing at the bottom of my controller.
When I try this, a map renders, but its not the address that i entered in my form.
How do I fix this? I don't have longitude and latitude attributes in my address table.
You geocoded class Address, so it has latitude and longitude method. Was User class geocoded too?
def index
#addresses = Address.all
#hash = Gmaps4rails.build_markers(#addresses) do |address, marker|
marker.lat address.latitude
marker.lng address.longitude
end
end
Be sure to add params to addresses:
class AddLatitudeAndLongitudeToAddress < ActiveRecord::Migration
def change
add_column :addresses, :latitude, :float
add_column :addresses, :longitude, :float
end
end
Let's check app/assets/javascripts/addresses.coffee
For example:
class RichMarkerBuilder extends Gmaps.Google.Builders.Marker
create_marker: ->
options = _.extend #marker_options(), #rich_marker_options()
#serviceObject = new RichMarker options
rich_marker_options: ->
marker = document.createElement("div")
marker.setAttribute 'class', 'marker_container'
marker.innerHTML = #args.marker
{ content: marker }
handler = Gmaps.build 'Google', { builders: { Marker: RichMarkerBuilder} }
handler.buildMap { provider: {}, internal: {id: 'map'} }, ->
markers = handler.addMarkers([
{"lat": 0, "lng": 0, 'marker': '<span>Here!</span>'}
])
handler.bounds.extendWith(markers)
handler.fitMapToBounds()
In your model add
geocoded_by :full_address
after_validation :geocode

get value of array in ajax, ruby on rails

I'm using ajax to check validate in client side, but i don't know how to get value in array of ruby on rails. Here is my ajax:
<script>
$(document).ready(function() {
$("#button").click(function() {
var email = $("#email").val();
var name = $("#username").val();
var phonenumber = $("#phonenumber").val();
var pass = $("#password").val();
var names = $("divname").toString();
console.log(names);
....
});
});
</script>
When i check Console.log, I just see "Object" but not values of array:
"[object Object]"
Here is my array, call by ruby on rails:
<% #usernames.each do |t| %>
<div id="divname"><%= t.username %></div>
<%end%>
Here my coontroller:
def index
#usernames = User.find(:all, :select => "username")
#user = User.create(:username => params[:username], :password => params[:password],
:email => params[:email], :phonenumber => params[:phonenumber])
if #user
render 'index'
else
render 'index'
end
So, please! help me to fix that :)
$("divname") is an jQuery object, so the result of toString() is "[object Object]".
id should be unique, use class instead.
<% #usernames.each do |t| %>
<div class="divname"><%= t.username %></div>
<%end%>
Then in js:
var names = $(".divname").map(function() {
return $(this).text();
}).get();
console.log(names);

geocode my location and display with google-maps-for-rails gem

i want to geocode my location and display with google-maps-for-rails gem
view:
= gmaps({ "map_options" => { "auto_adjust" => true } })
= form_tag geocode_geo_locations_path, :method => :get, :remote => true do
= text_field_tag 'address'
= submit_tag 'search'
in my controller i have:
def geocode
#location = Gmaps4rails.geocode(params[:address])
if #location
#location_hash = #location.map { |loc| {:longitude => loc[:lng], :latitude => loc[:lat], :address => loc[:matched_address]} }.first
end
end
and in the view geocode.js.erb
Gmaps4Rails.replace_markers(<%=raw #location_hash.to_json %>);
it work so far, that i get a marker on the map, however the map doesnt get auto_adjusted .
how can i accomplish that??
Ok... Indeed you just noticed a bug :)
Corrected now in 0.8.2.
Thanks!

Resources