I would like to seed my Rails app database with the permutation of an existing array of objects, and am unsure about the best way to go about this.
I currently have a Country model, with the following attributes:
create_table :countries do |t|
t.string :name
t.float :latitude_dec
t.float :longitude_dec
t.timestamps null: false
end
I have seeded this model from a .yaml file (as these attributes are static), and now would like to use these records to seed a CountryPair model (where the attributes are also static). This model will have the following attributes:
create_table :country_pairs do |t|
t.string :country_a
t.string :country_b
t.string :pair_name
t.float :country_a_latitude_dec
t.float :country_b_latitude_dec
t.float :country_a_longitude_dec
t.float :country_b_longitude_dec
t.float :distance
t.timestamps null: false
end
The aim is to permutate the array of Country objects, and create a CountryPair object from each permutation (and seed the database with the output). I understand the Ruby array#permutation method, but am unsure about how to pull out the appropriate values into the new array of CountryPair objects. The order of countries in the pair is important here, so I'd like to use permutations rather than combinations.
Ultimately, I'd also like to calculate the distance between the country pairs, but I'm hoping to start figuring that out once I have the CountryPair model filled!!
This is my first foray back into Rails after a five year absence, so apologies if I've got some of the terminology/methodology wrong - please do ask for clarification if any further information is required! Thanks in advance!
You can add this snippet to your seeds.rb after the Countries are seeded.
Country.all.permutation(2) do |p|
CountryPair.create(
country_a: p[0].name,
country_b: p[1].name,
pair_name: p[0]name + p[1].name,
country_a_latitude_dec: p[0].latitude.dec,
country_b_latitude_dec: p[1].latitude.dec,
country_a_longitude_dec: p[0].longitude.dec,
country_b_longitude_dec: p[1].longitude.dec,
distance: # An algorithm to calculate distance
)
end
Then run it with: rake db:setup
Related
I'm kind of new to Ruby on Rails. I have a profile model which has_many courses taken.
create_table "profiles", force: :cascade do |t|
t.string "pname"
t.float "current_gpa"
end
and
create_table "courses", force: :cascade do |t|
t.integer "course_number"
t.float "gpa"
end
I want to calculate the average gpa: current_gpa = sum of gpa of courses taken / num of course taken. How can I do this?
You should consider reading some documentation - obviously it's quick to get a answer on SO but sometimes the docs can lead you to something you didn't know to look for or ask for.
That said, the fastest way is to use average
profile.courses.average(:gpa)
This will give you an average. Or you can do it the long way, if for some reason you need make modifications in between.
profile.courses.sum(:gpa) / profile.courses.count
An additional note here... Average returns floating point numbers or BigDecimal which is often represented in decimal notation. This can be confusing and may not be what you are looking for. You might explore adding something like: .to_int, .to_f, .truncate, .round, etc...
Person.average(:age) # => 0.387e2
Person.average(:age).to_i # => 38
Person.average(:age).to_f # => 38.7
Person.average(:age).to_f.round # => 39
You can use ActiveRecord::Calculations average:
profile.courses.average(:gpa)
I'm trying to create an online football (soccer) management game with Ruby on Rails, and as it's quite ambitious for me I'm finding some parts fairly challenging. I've coded a basic match engine, but when it comes to tactics, lineups, formations, etc. I'm finding it more difficult to organise the various data and create relations in ActiveRecord. The same applies to league and cup systems.
I'll try to provide a brief overview here:
a nation/club has a first team and a youth/u21 team
a nation/club/team has players
a nation/club/team has matches against others in league and cup systems
a league system has three leagues in each division (pyramid system: 1 promoted, 3 relegated)
a cup system has knockout matches (and occasionally mini-league group stages) including extra time and penalty shootouts
a league/cup has rounds/match days for each season
a round/match day has matches
a match has details e.g. scores/ratings
a match has actions e.g. goal/assist
a match has tactics/lineups for each team e.g. formation/players
Any ideas how best to organise this in models?
Edit: What I'm mainly having trouble with is linking players to matches (via lineups?). Both teams need 11 of their players selected to play: 1 in goal and the remaining 10 outfield players spread across the defence/midfield/attack outfield positions, e.g. 4-4-2, etc. So Player 11 could be chosen to play in midfield, Player 9 in attack, Player 1 in goal, etc. Possible formations include 3-5-2, 3-4-3, 4-4-2, 4-5-1, 4-3-3, etc.
Here's a sample of the schema I'm attempting to use:
create_table "teams", force: :cascade do |t|
t.integer "nation_id"
...
end
create_table "players", force: :cascade do |t|
t.integer "nation_id"
t.integer "team_id"
...
end
create_table "matches", force: :cascade do |t|
t.integer "home_team_id"
t.integer "away_team_id"
...
end
create_table "lineups", force: :cascade do |t|
t.integer "match_id"
t.integer "team_id"
...
end
create_table "formations", force: :cascade do |t|
t.string "name"
...
end
create_table "positions", force: :cascade do |t|
t.integer "formation_id"
t.string "name"
...
end
Would something like this work? I'm not sure if the formations or positions tables are neccessary, or if that would even work.
This is not a Rails question per se - it is a general modelling question. There should be a large number of books, articles and tutorials on objectoriented modelling out there.
Without going into much detail here:
Basically, you also did most of the work by writing out your list.
Every word that is a substantive in your description leads to a (candidate for a) model. I.e.: nation, club, team, player, match, league-system, cup, league, division, match-day etc.
Draw those in boxes (google "UML class diagram" if you want to do it fancy). Those boxes correspond to files app/models/*.rb.
Draw a line between each of the boxes that have some kind of relationship (a.k.a., association) between them.
Mark out how many of each can be related (i.e., "each player can have zero or one team", "each team can have many players" etc.). This gives you to your has_many, has_one and belongs_to associations.
At the end, look for models that are just too trivial to have their actual Rails class. For example, the "day" might or might not be class-worthy (i.e., it could simply be a date attribute for your matches; but if you want to associate more information with the day per se, or if you want to plan matches which occur on the same day without having an actual date yet during the planning phase, then go ahead). Much of this is a matter of style, opinion and experience, there are no hard and fast rules here.
Check out the classical work "Design Patterns" for the introduction into modelling.
So, I'm using Rails 4, and I have an enum column on my "Sales_Opportunity" object called pipeline_status - this enables me to move it through a sales pipeline (e.g. New Lead, Qualified Lead, Closed deal etc). This all works fine. I'm able to find the number of sales_opportunities that a company has by status through using the following:
<%= #company.sales_opportunities.where(pipeline_status: 3).count %>
This all works fine. What I want to do is to find all sales_opportunities that have the pipeline_status of "closed_won" (enum value of 4 in my app) and sum the value of each won deal (so I can represent the total value of the customer based on the deals that are won in the system). A Sales_Opportunity in my model has a sale_value field, so I tried:
<%= #company.sales_opportunities.where(pipeline_status: 4).each.sale_value.sum %>
which returns the following error:
undefined method `sale_value' for #<Enumerator:0x007f9b87a9d128>
This is probably a trivial error but I can't for the life of me figure out what's going on. Is there where statement returning the enumerator or the sales_opportunity objects with that enumerator? Any help would be gratefully appreciated.
If it helps here are the fields in my sales_opportunities table:
create_table "sales_opportunities", force: true do |t|
t.datetime "close_date"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "pipeline_status", default: 0
t.string "opportunity_name"
t.integer "company_id"
t.decimal "sale_value", precision: 15, scale: 2, default: 0.0
end
A Sales_opportunity belongs_to a Company Object and a User Object, if that makes any difference.
use aggregate function sum
<%= #company.sales_opportunities.where(pipeline_status: 4).sum(:sale_value) %>
Other possibility is to use
<%= #company.sales_opportunities.where(pipeline_status: 4).pluck(:sale_value).reduce(0, :+) %>
I have an application that has tens of thousands of snapshot records. A very small number of these 'snapshots' (say 1 in 1000) will have one or more 'positions' through a :has_many association.
How can I efficiently discover if a snapshot has a position without firing an active record query for each snapshot? My current solution is to add a boolean field to snapshots - if a snapshot has a position, 'has_position' is set to true. This seems a little messy since it means I have to modify the associated snapshot every time I create a position. Is there a cleaner way to handle this scenario?
create_table "snapshots", :force => true do |t|
t.datetime "created_at",
t.datetime "updated_at",
t.boolean "has_position",
end
create_table "positions", :force => true do |t|
t.integer "snapshot_id"
t.datetime "created_at",
t.datetime "updated_at",
end
What will happen if you generate the migration for positions with the reference to snapshots, the migration file will be generated with a
add_index :positions, :snapshot_id
appended to the end of it.
With an index on snapshot_id the DB will take log(n) queries to figure out whether or not a position has at least one associated record. Not as good as constant time with the boolean, but with mere tens of thousands of records it shouldn't take noticeably longer (unless you're doing this very, very frequently).
Additionally, a simple has_position boolean might be harder than you think to maintain without an index. You can set it to true on creation of an associated position, but you can't set it to false on the deletion because there might exist another one, and you'd have to do a table scan again.
If for some reason using an index is undesirable (or you really need constant time lookup), then I'd recommend using a :counter_cache column.
This might seem like a duplicate question, but I can't find any information on this. I want to show the results from a remotely acquired json array excluding certain results by comparing them to a local table. I have a gallery model with:
t.integer :smugmug_id
t.string :smugmug_key
t.integer :category_id
t.string :category_name
t.string :description
t.integer :highlight_id
t.string :highlight_key
t.string :highlight_type
t.string :keywords
t.string :nicename
t.integer :subcategory_id
t.string :subcategory_name
t.string :title
t.string :url
The data for this model gets populated by a rake task that connects to the smugmug api (json) and stores the data locally. I'm trying to create a view that shows all the smugmug galleries that are not stored locally.
Here's what I've tried so far, but it's not excluding the locally stored galleries like I thought it would.
def self.not_stored
smugmug_list = Smug::Client.new.albums(heavy = true)
gallery_list = Gallery.select(:smugmug_id)
smugmug_list.each do |smugmug|
smugmug unless gallery_list.include? smugmug.id
end
end
Hopefully this makes sense. I'm getting a json array of galleries, and I want to display that array excluding results where the album id matches the smugmug_id of any of my locally stored records.
Quick edit: I'm using an adaptation of this gem to connect to the smugmug api.
Just use the difference operator.
General Example:
ruby-1.9.2-p136 :001 > [3,2,1] - [2,1]
=> [3]
So you would have:
smugmug_list.collect{|e| e.id} - gallery_list
Enumerable#collect will turn the smugmug_list into a list of id's. From there, you can do the difference operator, which will return all the id's of all the smugmug galleries that are not stored locally.
Another option to maintain the list of galleries:
smugmug_list.select{|e|!gallery_list.include?(e.id)}