RoR - Geokit plugin: why Location.find is giving me back an empty array? (Location is a model that "acts_as_mappable") - geokit

I have installed both geokit gem and geokit-rails plugin. I configured the plugin as shown here: http://github.com/andre/geokit-rails . Then I generated a new model - Location, which looks like this:
class Location < ActiveRecord::Base
acts_as_mappable :default_units => :kms
end
and a controller:
class TestController < ApplicationController
include GeoKit::Geocoders
include GeoKit::Mappable
def test1
#a=Geokit::Geocoders::YahooGeocoder.geocode 'Kaohsiung City, Taiwan'
#b=Location.find(:all, :origin => '100 Spear st, San Francisco, CA', :within => 5)
end
end
I also set up a Locations table with both lng and lat columns in my database and put my google key in /config/initializers/geokit_config.rb
And right now, altough #a is giving me correct results from YahooGeocoder (I can use GoogleGeocoder as well), #b is an empty array. I know #a is generated using Geokit gem and #b using Geokit-rails plugin, so the problem is definitely related to the plugin. When I use #c=IpGeocoder.geocode('85.128.202.178') I get "success: false" ... What am I doing wrong here?

Have you double checked your Location collection to ensure there exists a location within 5 kilometers of that street address? What happens if you do a similar lookup with an explicit latitude and longitude of a Location?
Re: #success=false, I'm having the same trouble with that IP (using IpGeocoder and MultiGeocoder).
>> #c=IpGeocoder.geocode('85.128.202.178')
=> #<Geokit::GeoLoc:0x1038df5f0 #success=false, #city="(Unknown City)", #province=nil, #street_address=nil, #lng=nil, #full_address=nil, #state=nil, #country_code="PL", #all=[#<Geokit::GeoLoc:0x1038df5f0 ...>], #lat=nil, #precision="unknown", #provider="hostip", #zip=nil>
>> #c=IpGeocoder.geocode('74.125.93.104')
=> #<Geokit::GeoLoc:0x1038d3c28 #success=true, #city="Manila", #province=nil, #street_address=nil, #lng=120.95, #full_address=nil, #state=nil, #country_code="PH", #all=[#<Geokit::GeoLoc:0x1038d3c28 ...>], #lat=14.5833, #precision="unknown", #provider="hostip", #zip=nil>

Related

Rails Store Array in Database

I need to persist an array in my rails language learning app. Here is the situation/reason I need to do this (if there is a better way please let me know). The user is presented, one at a time, 10 words to learn. After the words are learned they get quized on the same set of 10 words.
For the 'quiz' portion I would like to randomize the order the words appear in (for example: currently if you learn the words 1.fish 2.cat 3.dog... you will be quized in the same order 1.fish 2.cat 3.dog... which can make the quiz easier.
I need to persist it in case the user were to log off or navigate away. In this instance I want to return them to the exact word they left off on the quiz.
Here is the controller code I currently have:
def index
.
.
#quiz = Lang.limit(10).offset(current_user.bookmark - 11)
exercise_bank
.
.
end
private
def exercise_bank
current_user.random_exercise_array = (0..9).step(1).shuffle
current_user.save
#index2 = current_user.random_exercise_array[#index]
##index starts at 0 and increments on each call to index action
##index2 grabs the random number and uses it to reference a word in #quiz
#something like this: #quiz[#index2].spanish_to_english---grabs a english word
end
end
The idea of the above is to pick a random number 0-9 and use it to reference a word in my DB. The above results in something like the following in my DB for the random_exercise_array attribute:
random_exercise_array: "---\n- 6\n- 0\n- 1\n- 7\n- 8\n- 5\n- 9\n- 3\n- 2\n- 4\n"
Here is the relevant User DB code:
class DeviseCreateUsers < ActiveRecord::Migration
serialize :random_exercise_array
end
Relevant migration file:
class AddRandomExerciseArrayToUsers < ActiveRecord::Migration
def change
add_column :users, :random_exercise_array, :text
end
end
Is this the best way to solve this problem? If so, can you explain how to get back an integer from random_exercise_array without all of the (-)'s and (\n')s?
If you want get an array back from DB text column, you should declare the type in your user model like this:
class DeviseCreateUsers < ActiveRecord::Base #why your original code inherit from ActiveRecord::Migration?
serialize :random_exercise_array, Array
end
Then you can use current_user.random_exercise_array as an array instead of a string.

How to store users' location?

I am working on a new project and whole day thinking & looking for the best way, how to save users' location to database.
I need to save their city, country. Here is a bit problem, because for example for Europeans this means city=Berlin, country=Germany.
But for US users it's like city=Los Angeles, country=California (state=USA).
So this is the problem with which I ma facing whole today.
My goal in this app is to find all users in the city according to their location. And also find the people, which are in their area of let's say 15 km/miles.
I plan to implement the app in RoR, PostgreSQL, the app will run probably on Heroku.
What is the best way to solve this "problem"? Could you give me please some advices, tips, whatever?
Thank you
You can use the geokit and geokit-rails gems to achieve that. See here for documentation: https://github.com/imajes/geokit-rails
Basically, it works like this: you save address data of your users and that address is looked up and mapped to a point in space (lat/lng) using a geocoding service (e.g. Google Maps or Yahoo Placefinder). These points can then be used to calculate distances etc.
An example:
class User < ActiveRecord::Base
# has the following db fields:
# - city
# - state
# - country
# - latitude
# - longitude
acts_as_mappable :default_units => :miles,
:default_formula => :sphere,
:lat_column_name => :latitude,
:lng_column_name => :longitude,
:auto_geocode => {:field => :full_address}
def full_address
[city, state, country].reject(&:blank).join(', ')
end
end
Then you can do the following:
# find all users in a city (this has nothing to do with geokit but is just a normal db lookup)
User.where(:city => 'New York')
# find all users that are within X miles of a place
User.find_within(300, 'Denver')
and much more, just see the documentation...
This example shows you how to use the geokit gem. This gem does no longer seem to be under active development. So maybe it would be worthwile to check out geocoder: https://github.com/alexreisner/geocoder

get model with atleast one relation object in mongoid

I have a Person object which has_many companies. I would like to get the person with atleast one company.
What I can get right now is
Person.where(:company_ids.size => 1)
This will return all the person with one company . But I need something like
Person.where(:company_ids.size.gte => 1)
But it seems , this does not work.
Solution :
sorry for all the trouble, but found out that with previously created objects , I didn't have company_ids ... since I had only added that later. I can get the count with following :
Person.where(:company_ids.exists => true).and("this.company_ids.length > 0")
Thanks everyone for helping out.
I assume company_ids a array field in person document
I am afraid there is no way of specifying conditions in size. But there is a workaround using javascript $where expression
db.person.find({$where: '(this.company_ids.length > 0)'})
am not sure about how to pass this expression in mongoid.
EDIT
yeah you can do this with mongoid too
Person.where("$where" => 'this.company_ids.length >0;' )
You should be able to do:
Person.where("this.company_ids.length > 3")
Did you check doing as
Person.where("this.company_ids >=1")

assigning random url to a resource in rails 3

I need to generate a random url to my Topic model(for example) as such:
http://localhost:3000/9ARb123
So how can I do this in rails?
Note: the random string must contain digits, small and capital letters.
Something like this perhaps
#config/routes.rb
match "/:random_id" => "topics#show", :constraints => {:random_id => /([a-zA-Z]|\d){3,6}/}
will match a random string of 3-6 random letters/numbers to the show method of your Topics controller. Make sure to declare other resources above this matcher, as something like "http://localhost:3000/pies" will route to Topics#show instead of Pies#index.
To generate a random url for your Topic you can go something like this:
#app/models/topic.rb
before_create :generate_random_id
def generate_random_id
#generates a random hex string of length 6
random_id = SecureRandom.hex(3)
end
Patricks answer should work - but it only covers routing incoming requests.
If you're still using the standard routes (eg topic_path) to create your links, it will still use the normal routes.
If you run rake routes, you should see the name of the route you created with with the random_id. (You may need to name it using :as => 'random_route')
If you call that instead of the standard topic_path you should get the route you are after

Ruby On Rails: How to run safe updates

I'm using RoR and I want to do concurrency safe update queries. For example when I have
var user = User.find(user_id)
user.visits += 1
I get the following SQL code:
SELECT * FROM Users WHERE ID=1 -- find user's visits (1)
UPDATE Users SET Visits=2 WHERE ID=1 -- 1+1=2
But if there are several queries taking place at the same time, there will be locking problems.
According to RoR API I can use :lock => true attribute, but that's not what I want.
I found an awesome function update_counters:
User.update_counters(my_user.id, :visits => 1)
This gives the following SQL code
UPDATE Users SET Visits=Visits+1 WHERE ID=#something
Works great!
Now my question is how can I override the += function to do the update_counters thing instead?
Because
user.visits += 1 # better
User.update_counters(my_user.id, :visits => 1) # than this
UPDATE
I just created the following function
class ActiveRecord::Base
def inc(column, value)
User.update_counters(self.id, column => value)
end
end
Are there any other better ideas?
Don't know about better ideas, but I would define that method to the User class, not the ActiveRecord. And maybe increment_counter (that uses update_counters) would make it a bit more readable?
def inc(column, value)
self.increment_counter(column, value)
end
Haven't tested that and not saying this is definitely better idea, but that's probably how I'd do it.
Update:
And AFAIK you can't override the "+=", because "a += b" just a shortcut for "a = a + b" and you probably don't want to override "=" to use the update_counters :)