Join country calling codes to country table list - ruby-on-rails

I am creating a Rails project which requires a country table. I also like to include the country calling codes into them. I found help in creating the country table from GitHub and it looks like this:
class CreateCountries < ActiveRecord::Migration
def change
create_table :countries do |t|
t.string :name
t.string :printable_name
t.string :iso2, :size => 2
t.string :iso3, :size => 3
t.integer :numcode
t.timestamps
end
end
Country.reset_column_information
Country.create(:iso2 => 'AF', :name => 'AFGHANISTAN', :printable_name => 'Afghanistan', :iso3 => 'AFG', :numcode => '004')
Country.create(:iso2 => 'AL', :name => 'ALBANIA', :printable_name => 'Albania', :iso3 => 'ALB', :numcode => '008')
Country.create(:iso2 => 'DZ', :name => 'ALGERIA', :printable_name => 'Algeria', :iso3 => 'DZA', :numcode => '012')
and then I've also found a list of country calling codes and managed to put them in a spreadsheet:
Afghanistan 93
Albania 355
Algeria 213
What I'd like to a fast way to join the calling code into the above list so it looks like this:
Country.create(:iso2 => 'AF', :name => 'AFGHANISTAN', :printable_name => 'Afghanistan', :iso3 => 'AFG', :numcode => '004' :call_code => 93)
Any fast solution to achieve this using Excel or OpenOffice spreadsheet or MySQL?
Just as long as I don't have to key it in manually.

Copy your Country.create lines of code into Excel, say starting in A1.
Copy your list of codes into Excel and if necessary split into two
columns (eg with Text to Columns).
Name the result (say CArray).
In B1 put: =FIND("printable_name => '",A1)+19.
In C1 put:
=SUBSTITUTE(A1,")"," :call_code => "&VLOOKUP(MID(A1,B1,FIND("'",A1,B1)-B1),cArray,2,0)&")")
Copy B1:C1 down to suit.
Copy as much of ColumnC back in to your code as suitable.
cArray need not be in the same sheet.

Related

Rails and Chartkick

I'm trying to implement this style chart into my rails project.
<%= line_chart #goals.map{|goal|
{:name => goal.name, :data => goal.feats.group_by_week(:created_at).count }
} %>
I'm currently using Chartkick to do so. http://ankane.github.io/chartkick/
Here is how my tables are set up.
I want to track current_user Timesheets from 3 columns on my Timesheets table.
def change
create_table :timesheets do |t|
t.decimal :teacher
t.decimal :study
t.decimal :conversation
t.date :day
t.references :user
t.timestamps
end
add_index :timesheets, :user_id
end
That is currently what my Timesheet Table looks like. How can I go about tracking :teacher, :study, :conversation through a chart through chartkick? I've read through the documentation, and can't quite grasp it.
Thank you!
If I understand correctly, you want to do:
<%= line_chart [
{name: "Teacher", data: current_user.timesheets.map{|t| [t.day, t.teacher] }},
{name: "Study", data: current_user.timesheets.map{|t| [t.day, t.study] }},
{name: "Conversation", data: current_user.timesheets.map{|t| [t.day, t.conversation] }}
] %>

Thinking Sphinx - Showing the right record from the association

I have successfully got Thinking Sphinx working with Geolocation on an associated model. Happy days!
But I now need it to show the right associated record on a Google map.
The scenario is a Company with has_many offices. Offices have got the lng,lat values. I am searching on the Company and associating the offices to it.
E.g.
define_index do
indexes :name, :sortable => true
indexes offices(:city), :as => :city
indexes offices(:postal_code), :as => :postal_code
has "RADIANS(offices.lat)", :as => :lat, :type => :float
has "RADIANS(offices.lng)", :as => :lng, :type => :float
has created_at
has updated_at
set_property :latitude_attr => 'lat'
set_property :longitude_attr => 'lng'
set_property :field_weights => { 'name' => 10,
'service_name' => 9,
'city' => 8 }
end
Searching for x company in y location / postcode works perfectly, showing the correct companies that have got offices in the desired location within the #geodist radius.
E.g.
{:geo=>[0.9283660690549609, -0.050527407508941975], :sort_mode=>:expr, :sort_by=>"#weight * #weight / #geodist", :with=>{"#geodist"=>0.0..120700.8}, :conditions=>{:service_name=>"Business strategies"}, :page=>1, :per_page=>12, :star=>true}
The resulting records are company object, not the offices, which is fine for the list view but I want to show icons on a google map of the relevant associated office.
What is the best way to find the relevant associated office record to show within the radius bounds?
Sphinx only reliably handles single-value float attributes - and it has no concept of paired lat/lng values. This means that you can't have a solid search across objects with more than one lat/lng pair.
The best workaround is to actually search on Office instead - and perhaps pull in each office's company information:
define_index do
indexes company.name, :as => :name, :sortable => true
indexes city, postal_code
has "RADIANS(offices.lat)", :as => :lat, :type => :float
has "RADIANS(offices.lng)", :as => :lng, :type => :float
has company.created_at, :as => :created_at
has company.updated_at, :as => :updated_at
has company_id
set_property :field_weights => {
'name' => 10,
'service_name' => 9,
'city' => 8
}
end
And then when searching, you can group by company_id to ensure only one result for any company (if that's what you'd prefer):
Office.search 'foo',
:geo => [lat, lng],
:with => {'#geodist' => 0.0..120700.8}
:group_function => :attr
:group_by => 'company_id'
If it's important as to which Office gets returned for a given company_id, then you'll probably want to use the :group_clause option as well. The docs cover this.

How do you seed models with HABTM relationships to other seeded models

I'm working on my first Rails(3) App, and looking to seed a bunch of data.
The issue I'm having is that I want to seed some models that have a has_and_belongs_to_many relationship with other models I've just seeded. I'm doing what seems right, but I'm not getting the results I'm expecting.
I have an Asana model (simplified):
class Asana < ActiveRecord::Base
has_and_belongs_to_many :therapeutic_foci
end
and the TherapeuticFocus model:
class TherapeuticFocus < ActiveRecord::Base
has_and_belongs_to_many :asanas
end
In my db/seeds.rb, I create some TherapeuticFoci:
tf = TherapeuticFocus.create([
{:name => 'Anxiety'},
{:name => 'Asthma'},
{:name => 'Fatigue'},
{:name => 'Flat Feet'},
{:name => 'Headache'},
{:name => 'High Blood Pressure'},
{:name => 'Stress'} ])
Then create an Asana:
asanaCreate = Asana.create!([
{ :english_name => 'Mountain Pose',
:traditional_name => 'Tadasana',
:pronunciation => 'TadaSANA',
:deck_set => 'Basic',
:type => 'Standing',
:therapeutic_foci => TherapeuticFocus.where("name in ('Stress','Flat Feet')")}
])
The result is that the TherapeuticFocus models are created, the Asana is created, but it doesn't create the relationships to the TherapeuticFocus models. The resulting array is empty.
If I run
TherapeuticFocus.where("name in ('Stress','Flat Feet')")
in the rails console, I get the expected two records:
irb(main):010:0> TherapeuticFocus.where("name in ('Stress','Flat Feet')")
=> [#<TherapeuticFocus id: 6, name: "Flat Feet", description: nil, created_at: "2010-10-11 01:48:02", updated_at: "2010-10-11 01:48:02">,
#<TherapeuticFocus id: 19, name: "Stress", description: nil, created_at: "2010-10-11 01:48:02", updated_at: "2010-10-11 01:48:02">]
So, how does one do this?
Or, is there a better way to do this?
Thanks!
POST ANSWER:
I had already added the inflection:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'focus', 'foci'
end
My migration for the join tables looks like:
create_table :asanas_therapeutic_foci, :id => false do |t|
t.references :asana, :therapeutic_focus
end
I'll try changing this to t.belongs_to instead of t.references and see if that works.
Did you register the pluralization for “focus”? It is not defined by default, so you will need to define it (usually in config/initializers/inflections.rb):
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'focus', 'foci'
end
You also need to make sure your migration has defined the correct join table for the HABTM association. Here is the pertinent part of the “up” migration that I used:
create_table :asanas do |t|
t.string :english_name
t.string :traditional_name
t.string :pronunciation
t.string :deck_set
t.string :type
end
create_table :therapeutic_foci do |t|
t.string :name
end
create_table :asanas_therapeutic_foci, :id => false do |t|
t.belongs_to :asana
t.belongs_to :therapeutic_focus
end
I used the models as you quoted.
With those bits in place, I was able to load your seed definitions.

Paginate with order defined by joined model in Rails

I have currently the following problem in my Rails application (Rails 2.3.5):
I want to sort books stored in the application by the author name, then the title of the book.
Book and Author are concrete models, the corresponding tables are Ressources and People. The relevant portion of the schema is (I have stripped down the model a bit):
create_table "people", :force => true do |t|
t.string "sur_name"
t.string "pre_name"
...
t.string "type"
end
create_table "people_ressources", :id => false, :force => true do |t|
t.integer "ressource_id"
t.integer "person_id"
end
create_table "ressources", :force => true do |t|
t.string "type"
t.string "title"
end
To show the list of books, I have used the following paginator:
#books = Book.paginate(
:order => 'title', :per_page => 15, :page => params[:page])
My question now is: How should the paginator be constructed so that the books are ordered not by title, but first by author (== person) sur_name? And if that is not easily reachable, what construct would allow to store books and authors as separate entities, but would allow to get a paginator with the defined order?
Given that you have multiple authors for a book you would need to decide how you determine which is the author whose name should be used to order the list of books.
You could add an association has_one :main_author, :class_name => 'Author' to your Book class defined however you wish (maybe there is a primary author field in people_ressources or maybe you just use the first author available:
has_one :main_author, :through => :author_books, :order => 'sur_name'
Having that has_one association means that you can include that in the pagination and order against the sur_name there:
#books = Book.paginate(:order => "#{Author.table_name}.sur_name",
:per_page => 15,
:page => params[:page])

How can I transparently modify an ActiveRecord method in a model?

I have a model with UUIDs stored in BINARY(16) field in a MySQL table. I would like to be able to transparently convert hexadecimal uuid into binary for the setter method and back when I use the getter method.
what is the 'right' way to proceed?
You override the setter and getter:
class User < ActiveRecord::Base
def uuid=(value)
#uuid = write_attribute(:uuid, value.scan(/../).map {|n| n.to_i(16)}.pack("C*"))
end
def uuid
#uuid ||= read_attribute(:uuid).unpack("C*").map {|n| sprintf("%02x", n)}.join
end
end
Of course, you'd want a BINARY column, because you're sending raw bytes to the DB. A migration such as this one:
class AddUuidToUsers
def self.up
execute "ALTER TABLE users ADD uuid BINARY(16)"
end
end
I looked at the source code for ActiveRecord 2.3.5 (mysql_adapter.rb). Looking at the NATIVE_DATABASE_TYPES hash makes it clear that it does not support the BINARY(16) data type:
NATIVE_DATABASE_TYPES = {
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
:string => { :name => "varchar", :limit => 255 },
:text => { :name => "text" },
:integer => { :name => "int", :limit => 4 },
:float => { :name => "float" },
:decimal => { :name => "decimal" },
:datetime => { :name => "datetime" },
:timestamp => { :name => "datetime" },
:time => { :name => "time" },
:date => { :name => "date" },
:binary => { :name => "blob" },
:boolean => { :name => "tinyint", :limit => 1 }
}
Also note that :binary is not what you want, because that creates a BLOB column.
If you have the inclination, I would recommend extending ActiveRecord to support the BINARY(16) type.
Update: after some searching the following blog post by Matthew Higgins seems to be promising ("While arbitrary SQL statements can be executed in migrations, an alternative is to extend the MySql adapter to support new types of columns."):
http://www.strictlyuntyped.com/2008/07/mysql-lovin-part-2-adding-new-column.html
If you get this to work, I would hope that you share what you come up with. Like Matthew, I would like to see ActiveRecord have a cleaner API for adding column types.

Resources