Rails Active Model Association Issue - mysql

I am having an issue with model associations. I want to pull a route's trip info by accessing the data from trips.route_id where routes.route_id would be the same value. Currently the SQL query is calling routes.id, instead using routes.route_id. Any help would be appreciated.
Route Table Structure
COLUMNS: id,route_id,route_short_name,route_long_name,route_desc,route_type
ROW: 1,2-36,2,"East 34th St",,3
The primary_key on this table is 'id'.
Models
class Route < ActiveRecord::Base
has_many :trips, :foreign_key => 'route_id'
end
class Trip < ActiveRecord::Base
belongs_to :route
end
Route Controller
class RouteController < ApplicationController
def show
#route = Route.where("'%s' = routes.route_short_name",params[:id]).first
end
end
Want to call #route.trips to pull trip information associated with said #route
LOG INFO
Started GET "/route/19" for 127.0.0.1 at Wed Nov 23 21:09:55 -0500 2011
Processing by RouteController#show as HTML
Parameters: {"id"=>"19"}
Route Load (0.4ms) SELECT `routes`.* FROM `routes` WHERE ('19' = routes.route_short_name) LIMIT 1
Trip Load (8.4ms) SELECT `trips`.* FROM `trips` WHERE `trips`.`route_id` = 15
Trip Load Explanation: 15 represents the id of the object returned from the "Route Load" query. I would like to use the routes.route_id value of the result instead of the id to build the "Trip Load" query.
Desired result:
Trip Load (8.4ms) SELECT 'trips'.* FROM 'trips' WHERE 'trips'.'route_id' = '2-36'
('2-36' value is referenced from Route Table Structure example)

If I understand your question properly, you need to change your models to something like this:
class Route < ActiveRecord::Base
has_many :trips, :primary_key => "route_id"
end
class Trip < ActiveRecord::Base
belongs_to :route, :primary_key => "route_id"
end

Related

Rails 4 - how to generate statistics through "joins" and "includes" commands in Activerecord?

I kind of stuck at trying to generate statistics for my application. The relevant part of the application has the following structure:
class CarRegistration < ActiveRecord::Base
belongs_to :ride
belongs_to :car
...
end
class Car < ActiveRecord::Base
has_many :car_registration
...
end
class Ride < ActiveRecord::Base
belongs_to :passenger
belongs_to :driver
has_many :car_registration
...
end
class Driver < ActiveRecord::Base
has_many :cars
...
end
class Passenger < ActiveRecord::Base
has_many :cars
...
end
I am trying to get a list of rides, top drivers and and top passengers. I originally tried something like this:
#rides_finished = Ride.joins(:car_registration)
.select('rides.id')
.where("(car_registrations.ride_id = rides.id)
AND rides.status = 3
AND rides.driver_currency = ?
AND rides.passenger_currency = ?", currency, currency)
.distinct # against displaying one shipment multiple times
And then I tried:
#top_pasengers = #rides_finished.joins(:passenger)
.select('passengers.id, passengers.name, count(rides.passenger_id) AS count_all')
.where('rides.passenger_id IS NOT NULL')
.group('passengers.id')
.order('count_all DESC')
.limit(10)
But when I run these queries, I get
Mysql2::Error: Unknown column 'count_all' in 'order clause': ...
Any help how to get the needed numbers?
Thank you very much
Your question is a little confusing because your query uses Ride but there is no Ride in the model definitions listed. I've focussed purely on the example queries you listed.
I think it would be easier to start with a single query chain for 'top passengers':
Passenger
.select('passengers.*')
.select('count(1) as ride_count')
.joins(:rides)
.where(rides: { status: 3,
driver_currency: currency,
passenger_currency: currency })
.group('passengers.id')
.order('ride_count desc')
.limit(10)
That will get you an ActiveRecord::Relation of Passenger models that also respond to a ride_count call, e.g. you could use it like:
results.each do |p|
puts "#{p.name}: #{p.ride_count}'
end
If all that works, you should be able to adjust the query to get the top drivers.
To get the list of finished rides, I suggest a separate, simple query:
Ride.where(status: 3,
driver_currency: currency,
passenger_currency: currency)
Let me know if any of that produces an error.

Storing Location Data in the Database

I need to store data about specific Objects which include information about Location(Country, City, District) of an object. I'm trying to figure out the best way to store described above location data in the MySQL database and how it should look like in the rails active model.
My dummy idea is to create 3 separate tables like below:
Location_countries
id
name
Location_cities
id
country_id
name
Location_districts
id
city_id
name
Create a separate table for an object and call it the item_location and include Ids of object its country... so on
Next is to create 3 Rails models (Country, City, Districts).. , but I think it's a very dirty way and it can be combined into the single Model like Item_location
Any Ideas?
Thank you in advance!
I don't entirely understand what you're looking to do, but either way, here's how I'd tackle it:
#app/models/object.rb
Class Object < ActiveRecord::Base
has_one :location
end
#app/models/location.rb
Class Location < ActiveRecord::Base
belongs_to :object
belongs_to :city
belongs_to :district
delegate :name, to: :city, prefix: true
delegate :name, to: :district, prefix: true
end
#app/models/city.rb
Class City < ActiveRecord::Base
has_many :locations
belongs_to :country
end
#app/models/district.rb
Class District < ActiveRecord::Base
has_many :locations
end
#app/models/country.rb
Class Country < ActiveRecord::Base
has_many :cities
end
This will give you the ability to call:
#object = Object.find params[:id]
#object.location.city_name
#object.location.district_name

Query processing time is more..performance issue in retrieving data

I have bit complicated model design with many associations among themselves.
Here is model design
User Model
class User < ActiveRecord::Base
has_many :records
validates :email, presence: true
end
Record Model
class Record < ActiveRecord::Base
belongs_to :user
has_many :record_type_student
has_many :record_type_employee
has_many :record_type_other
end
RecordTypeStudent Model
class RecordTypeStudent < ActiveRecord::Base
belongs_to :record
belongs_to :user
belongs_to :source
end
Similar Model for other two RecordTypeOther and RecordTypeEmployee
I have Added index as well in RecordTypeStudent, Other and Employee from Record for fast retrieval.
Currently retreiving 1000 records including all three takes 2.4 seconds which I think is alot.
Here is how I am querying my records
first Query
#records = Record.where(:user_id => 1)
#r = []
#records.each do |m|
if !r.record_type_students.empty?
#r += r.record_type_students
end
if !r.record_type_other.empty?
#r += r.record_type_others
end
if !r.record_type_employees.empty?
#r += r.record_type_employees
end
end
The processing time is very low and it is only 1000 records so I am not sure is bad queries that I am doing or something else.
Application is using MySQl for data base
Completed 200 OK in 2338ms (Views: 0.5ms | ActiveRecord: 445.5ms)
It seems to me like you are creating a lot of unnecessary queries. Instead of pulling out the records and iterating over them (which should have been done with .find_each rather than .each), you can query the individual record types with the right records which will result in an IN clause and will be done on the database side. If I am understanding your schema correctly, you can get the same data as follows (AR 4.1.1):
record = Record.where(user_id: 1)
r = []
r += RecordTypeStudent.where(record: record).to_a
r += RecordTypeEmployee.where(record: record).to_a
r += RecordTypeOther.where(record: record).to_a
This will result in 3 queries total. You can make the code cleaner as follows:
r = [RecordTypeStudent, RecordTypeEmployee, RecordTypeOther].flat_map do |type|
type.where(record: Record.where(user_id: 1)).to_a
end
If you want to further drop the number of queries, you could get the data via UNION between those tables but I don't think that's necessary.
I guess it's just here in the question's text but those has_many in the Record model have to be specified with plural arguments, otherwise it won't work.

ActiveRecord custom has_many association makes multiple calls to the database

I have a pair of ActiveRecord objects that have a belongs_to ... has_many association, with the has_many association being custom-made. Example:
First AR object:
class Car < Vehicle
has_many :wheels, class_name: "RoundObject", foreign_key: :vehicle_id, conditions: "working = 1"
validates_presence_of :wheels
...
end
Second AR object:
class RoundObject < ActiveRecord::Base
belongs_to :vehicle
...
end
Please note that the above is not indicative of my app's function, simply to outline the association between my two AR objects.
The issue I'm having is that, when I reset the cache (and thus my Rails app re-caches all AR objects in the database), when it comes time for the RoundObject object to get re-cached, it makes multiple calls to the database, one for each unique vehicle_id associated with the collection of RoundObjects. The SQL commands being run are output to the console, so this is what my output looked like:
RoundObject Load (2.0ms) SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 28 AND (active = 1)
RoundObject Load (1.0ms) SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 29 AND (active = 1)
RoundObject Load (2.0ms) SELECT `round_objects`.* FROM `round_objects` WHERE `round_objects`.`vehicle_id` = 30 AND (active = 1)
My app has several other AR objects that use the built-in has_many association without any modifications, and I notice that they only hit the database once when resetting the cache. For instance:
Micropost Load (15.0ms) SELECT `microposts`.* FROM `microposts` INNER JOIN `posts` ON `posts`.`id` = `microposts`.`post_id` WHERE `microposts`.`active` = 1 AND `posts`.`active` = 1
My question is, how can I make my AR object only hit the database once on cache reset, while still maintaining the custom has_many association I need? Can I manually force a join on the SQL query being called, and will this help?
Thank you!
You can use includes method while calling your Vehicle object to include the RoundObject.
It will go like this:
Vehicle.where(conditions_for_getting_data).includes(:round_object)

How do I iterate over an array with Ruby so that it saves individual records in MySQL?

In my HTML, I am able to return an array from a select multiple box using
<select multiple id="purchases" name="purchases[]">
<option value="purchase1">Shoes</option>
<option value="purchase2">Dress Shirts</option>
</select>
My goal is to create a new database record for each of the options selected (I'm using Ruby on Rails and MySQL.) However, my controller isn't saving each value in its own record:
Controller
#purchase = Purchase.new(params[:purchases])
#purchase.purchaseinfo = params[:purchases]
Purchase Model
class Purchase < ActiveRecord::Base
belongs_to :customer
end
Customer Model
class Customer < ActiveRecord::Base
belongs_to :account
has_many :purchases
end
I know I should iterate through the controller, but I'm not sure how. Thanks in advance for your advice!
Edit 1
No matter what I do in the controller, the log tells me that the whole array, "purchases", is being sent, not the individual records. Here is the log and here is the current controller.
LOG
Processing SavedcustomerController#create (for IP at DATE TIME) [POST]
Parameters: {"purchases"=>["Item1", "Item2", "Item3"]}
Redirected to http://example.com/maptry
Completed in 21ms (DB: 2) | 302 Found [http://example.com/]
SavedcustomerController#Create
items_array = params[:purchases].split('"\"\"",')
items_array.each do |arrayitem|
#purchase = Purchase.new(params[:purchases])
#purchase.purchaseinfo = arrayitem
end
If you are on Rails 3 and you add attr_accessible :purchase_info to your Purchase model you could do this.
purchases = params[:purchases]
#purchases = purchases.map { |purchase| Purchase.create(purchase_info: purchase) }
UPDATE
In the most simple way you should be able to just do
purchases = params[:purchases]
purchases.each do |purchase_info|
purchase = Purchase.new
purchase.purchase_info = purchase_info
purchase.save
end
I'm not sure if attr_accessible was in Rails 2 but that code up there should work... are you getting any exceptions/errors with the code I provided?
Can you try this:
items_array = params[:purchases]
items_array.each do |arrayitem|
#purchase = Purchase.new()
#purchase.purchaseinfo = arrayitem
end
In Purchase.new() you should put all other attributes you want