geokit-rails getting the route passing close to 2 points - ruby-on-rails-4

I'm having a route model
class Route < ActiveRecord::Base
has_many :etapes
acts_as_mappable :through => :steps
end
and a step one (that contains lat and lgn)
class Step ActiveRecord::Base
belongs_to :route
acts_as_mappable
end
Actually, I can get the routes passing close to one point with the in_range scope : Route.joins(:steps).in_range(0..15, :origin => [lat, lng]).group(:id)
I'm trying to get the route passing close to 2 steps, acts_as_mappable does not have the scope I need, so I'm wondering what the best way to go ?

Well, to those having similar issue, I did it like this.
Given a hash with 4 points (2 lat and lng);
ids = Route.joins(:steps).in_range(0..15, :origin => [hash[:lat1], hash[:lng1]]).group(:id).map(&:id)
routes = Route.joins(:steps).in_range(0..15, :origin => [hash[:lat2], hash[:lng2]]).group(:id)
routes.select {|route| ids.include? route.id}
I first take the routes in range with my first point, then the routes in range with my second point and I select in my first routes only the one in the second routes.

Related

Rails 4 polymorphic has_many ignores table_name

Short version: I'm building a new Rails 4 application that uses (read-only) some tables from a database used by a legacy Rails 2 application, which is still in use. The old application models/tables were very confusingly named, however (especially in the context of the new application), so I want to use different names for the models/tables using self.table_name. This all works perfectly until I tried to add in a polymorphic relationship. Rails ignores my defined table_name and does a query on the type using the new model name, which of course is different so it doesn't work. Is there any way to change this?
Long version: There are three models in this equation, and here they are:
class Exporter < MysqlBase
has_many :lic_exporter_addresses, :as => :place
self.table_name = 'excons'
self.primary_key = 'id'
end
class LicBusiness < MysqlBase
has_one :physical_address, -> { where(category: 'Physical') }, :class_name => 'LicExporterAddress', :as => :place
has_one :mailing_address, -> { where(category: 'Mailing') }, :class_name => 'LicExporterAddress', :as => :place
has_many :lic_exporter_addresses, :as => :place
self.table_name = 'businesses'
self.primary_key = 'id'
end
class LicExporterAddress < MysqlBase
belongs_to :place, polymorphic: true
self.table_name = 'addresses'
self.primary_key = 'id'
end
We have a ton of different kinds of businesses, so the Business model is the most problematic. I really don't want to have that in the new app because it would be very confusing as to what a "business" actually is. With the current code if I go into the rails console and try to get lic_exporter_addresses for a LicBusiness or Exporter, it does:
SELECT `addresses`.* FROM `addresses` WHERE `addresses`.`place_id` = '00044c693f6848f9b0978f873cf9999a' AND `addresses`.`place_type` = 'LicBusiness'
when what I need is place_type = 'Business'.
Is there any way to tell Rails what place_type to look for? I did see this question and the second answer looked promising, except that I'm already sort of doing that with Physical and Mailing addresses so I can't figure out how that'd work with both options at the same time... Thanks for any info or ideas.
In Rails 4.2, it looks like the exact string used for the query is defined as owner.class.base_class.name, where owner is the model declaring the association. So I don't think it's directly supported. But there are a few ways I can think of to hack around this. I think the most promising might be, in LicBusiness:
has_many :lic_exporter_addresses, ->{where place_type: "Business"}, foreign_key: "place_id"
That is, don't define the association as polymorphic, but define the type scope yourself. This will NOT correctly define place_type in the lic_exporter_addresses table if you ever use lic_exporter_address.place = some_lic_business_instance. However you said this table was read-only, so this may in fact not be an issue for you. If it is, there may be ways to override the behavior to get what you need.
Two other ideas both make me very nervous and I think they are probably quite dangerous for unintended side-effects. They are to override LicBusiness.base_class (this might actually be ok if you do not now and never will have STI set up on LicBusiness, but I'm still nervous), or to override LicBusiness.name (I'm pretty sure this would have unintended side-effects).

How do I get a set of objects belonging to another set of objects in Rails 4 ActiveRecord?

If I have two models, say, an user Model and a Company model like those defined below. How do I get all of the companies of a set of users?
class User < ActiveRecord::Base
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :users
end
users = User.where(:state => "Florida")
From this, I need a variable that holds all of the companies belonging to those users
companies = users.?
Do I need to loop through each of the users and add them to an array? I'm guessing there is a better way to do this. Any help is appreciated.
You can do this
Company.includes(:users).where(users: { state: 'Florida' })
BUT Taking into account http://guides.rubyonrails.org/ recommendations
It will be more correct to do
Company.joins(:users).where(users: { state: 'Florida'})
This does INNER JOIN instead of LEFT OUTER JOIN

Can I make a belongs_to association use eager loading by default?

I am connecting to one of my company's SQL Server databases, and trying to set up ActiveRecord so I can treat them just the same as Rails objects.
I have these two models:
class Change < ActiveRecord::Base
belongs_to :affected_contact, class_name: "Contact"
end
class Contact
# Contact's primary key is a binary UUID; I can't change this
end
I am trying to get the affected contact of one particular change. Normally, this would be a simple case, but:
Change.first.affected_contact
Change Load (52.6ms) EXEC sp_executesql N'SELECT TOP (1) [chg].* FROM [chg] ORDER BY [chg].[id] ASC'
Contact Load (28.0ms) EXEC sp_executesql N'SELECT TOP (1) [ca_contact].* FROM [ca_contact] WHERE [ca_contact].[contact_uuid] = #0', N'#0 binary', #0 = 0xfcf9a8ac6381aa4386c9b10ee382e10b [["contact_uuid", "<16 bytes of binary data>"]]
=> nil
... that's not what I want! And yet, if I eager-load the join first, it works:
Change.eager_load(:affected_contact).first.affected_contact
SQL (34.4ms) EXEC sp_executesql N'SELECT TOP (1) holy_crap_theres_a_lot_of_columns FROM [chg] LEFT OUTER JOIN [ca_contact] ON [ca_contact].[contact_uuid] = [chg].[affected_contact] ORDER BY [chg].[id] ASC'
=> #<Contact contact_uuid: "\xFC\xF9\xA8\xACc\x81\xAAC\x86\xC9\xB1\x0E\xE3\x82\xE1\v", ... >
In fact, if I force the matching to happen in the JOIN clause in any way, it will work, but belongs_to seems to use the WHERE clause instead, and nil is the best response I can get (a lot of the time, there are conversion errors between the string and its binary type).
Is there a way to ensure eager-loading through the JOIN clause happens by default on the belongs_to association?
I found that #find_by_contact_uuid (contact_uuid being the primary key) worked, where #find didn't, for some reason. That led to this being implemented.
I have ended up essentially rewriting the association methods that Active Record supplies:
module AssociationMethods
def self.included(base)
base.reflect_on_all_associations(:belong_to).each do |a|
define_method a.name do
# #find_by_<uuid_pk> seems to work where #find doesn't
a.klass.send "find_by_#{a.association_primary_key}", self[a.foreign_key]
end
end
base.reflect_on_all_associations(:has_many).each do |a|
define_method a.name do
a.klass.where(a.foreign_key => self.send(a.association_primary_key))
end
end
end
end
class Contact
has_many :changes, foreign_key: :affected_contact_id
include AssociationMethods # include *after* all associations are defined
end
class Change
belongs_to :affected_contact, class_name: 'Contact'
include AssociationMethods
end
It doesn't cover everything that Active Record supplies when setting up the associations, but it seems to do the trick.
Using includes should resolve your problem. This is because includes will preload or eager_load depending on your other conditions.
read more here

has_many multiple associations with different names

Ruby 2.1.0/Rails 4.0.2
I have a Bus model and a Cluster model. They look as follows:
class Bus < ActiveRecord::Base
has_many :left_centroids, class_name: "Centroid"
has_many :right_centroids, class_name: "Centroid"
end
class Centroid < ActiveRecord::Base
belongs_to :bus
end
Bus also has a method that is basically KMeans Algorithm, so I run it to replace the old left_centroids and then to replace the right_centroids. Right and Left differ in the value of a given field from the Centroid Model.
I have tried saving those via simple setting: #bus.left_centroids = centroids_for_algorithms and also through update_attributes. But whenever I save one, say left, right is overwritten with the values of left, and the other way around, which is pointless in the context of my application.
Am I missing something?
UPDATE: After I run the K Means Algorithm (from the ai4r gem, link in comments), I collect the centroids
def algorithm(direction)
clusters = k_means_algorithm_part
centroids_to_add_to_bus = Centroid.limit 0
clusters.centroids.each do |centroid|
cent = Centroid.create(
:latitude => centroid[0].to_d,
:longitude => centroid[1].to_d,
:catch_time => centroid[2],
:direction => direction,
:bus_id => bus_id
)
centroids_to_add_to_bus.append cent
end
bus = Bus.find(bus_id)
if direction
bus.right_centroids = centroids_to_add_to_bus
else
bus.left_centroids = centroids_to_add_to_bus
end
end
Can you add another column in the centroids table called type. Now you can use this to apply conditions on your associations. Like this
class Bus < ActiveRecord::Base
has_many :left_centroids, class_name: "Centroid", -> { where type: 'left_centroid' }
has_many :right_centroids, class_name: "Centroid", -> { where type: 'right_centroid' }
end
Not sure of the syntax, but I think this should help.

Adding has_and_belong_to_many entity using static method

I have two models :
class Candidate < ActiveRecord::Base
has_and_belongs_to_many :skills
end
class Skill < ActiveRecord::Base
has_and_belongs_to_many :candidates
def self.add
find_or_create_by(name:"management")
end
end
The following execution seems to work fine :
>current_candidate.skills.count
=> 0
>current_candidate.skills.find_or_create_by(name:"mathematics")
=> ...
>current_candidate.skills.count
=> 1
But here is what happen when I use the static method add :
>current_candidate.skills.count
=> 0
>current_candidate.skills.add
=> ...
>current_candidate.skills.count
=> 0
The skill management is created, but not binded to my candidate entity.
I don't understand why the static method doesn't consider the current_candidate.
PS: It works well with direct binding (like has_many and belongs_to)
New answer (previous answer deleted):
Your code will not work because you have defined add as a class method of Skill. The class Skill has no relation to candidates. An instance of a Skill does have a relation to candidates.
So to fix this, I think it makes more sense to add an add_skill method on Candidate and remove the one in Skill.
class Candidate < ActiveRecord::Base
has_and_belongs_to_many :skills
def add_skill(skill_name)
skills.find_or_create_by(name: skill_name)
end
end
Usage:
current_candidate.add_skill('a_skill')
As stated in my previous answer, you might want to replace the find_or_create_by call with the bang version find_or_create_by! to catch (validation) errors.