AR: dynamic accessors don't always work?

This is curious. Consider 'record' below, derived from an SQL query. Notice that record.station_id returns the station id properly, but record.start_time returns nil. What's the difference? (FWIW, I *can* access the start_time via the construct record[:start_time]).

This took me a while to track down, so I need to know: what's the difference between the two fields? And - more importantly - what part of the documentation explains what's going on?

record

=> #<WeatherObservation precipitation_m: 0.0>

record.station_id

=> "KCAMILLV8" # got the station id

record.start_time

=> nil # where's the start time?

record[:start_time]

=> "2007-01-01 00:00:00" # ah - there it is! but wtf?

record.attributes

=> {"end_time"=>"2007-01-02 00:00:00", "precipitation_m"=>0.0, "start_time"=>"2007-01-01 00:00:00", "station_id"=>"KCAMILLV8", "temperature_c"=>"8.88889"}

I'm not sure this is germane to the problem, but here's the SQL query that produced the record. NOTE: neither "station_id" nor "start_time" are 'native' slots in the WeatherObservation class:

    SELECT st.datetime AS start_time,            et.datetime AS end_time,            ws.station_id AS station_id,            wo.temperature_avg_c AS temperature_c,            wo.precipitation_m AS precipitation_m       FROM weather_observations AS wo INNER JOIN weather_stations AS ws ON wo.weather_station_id = ws.id INNER JOIN time_dimensions AS st ON wo.start_time_id = st.id INNER JOIN time_dimensions AS et ON wo.end_time_id = et.id      WHERE ws.id IN (#{station_ids}) AND            st.datetime BETWEEN \'#{start_date}\' and \'#{end_date}\' AND            et.datetime BETWEEN \'#{start_date}\' and \'#{end_date}\'

... all wrapped up in WeatherObservation.find_by_sql(), of course.

what columns does weather_observations have ? From glancing at the relevant bit of the internals i think an odd thing might happen if weather_observations itself had a start_time column of its own that was of a different type to the data grabbed here

Fred

Frederick Cheung wrote:

what columns does weather_observations have ? From glancing at the relevant bit of the internals i think an odd thing might happen if weather_observations itself had a start_time column of its own that was of a different type to the data grabbed here

Fred

I had the same thought, but while WeatherObservation has a start_time_id, but it doesn't have a start_time slot. Is AR being clever about foreign key references? Here's the schema:

  create_table "weather_observations", :id => false, :force => true do

t>

    t.integer "start_time_id"     t.integer "end_time_id"     t.integer "weather_station_id"     t.float "temperature_max_c"     t.float "temperature_avg_c"     t.float "temperature_min_c"     t.float "dewpoint_max_c"     t.float "dewpoint_avg_c"     t.float "dewpoint_min_c"     t.float "humidity_max"     t.float "humidity_avg"     t.float "humidity_min"     t.float "pressure_max_kpa"     t.float "pressure_avg_kpa"     t.float "pressure_min_kpa"     t.float "windspeed_max_mps"     t.float "windspeed_avg_mps"     t.float "gustspeed_max_mps"     t.float "precipitation_m"   end

is there a belongs_to :start_time ? If so then it's the accessor for that association that's being called, not the attribute reader (and it's nil because the object at hand has no start_time_id

Fred

Frederick Cheung wrote:

is there a belongs_to :start_time ? If so then it's the accessor for that association that's being called, not the attribute reader (and it's nil because the object at hand has no start_time_id

Fred

Give this man a cigar! That's exactly what's going on.

class WeatherObservation < ActiveRecord::Base   belongs_to :start_time, :class_name => 'TimeDimension', :foreign_key => 'start_time_id'   belongs_to :end_time, :class_name => 'TimeDimension', :foreign_key => 'end_time_id'   belongs_to :weather_station ... end

The ActiveRecord::Associations::ClassMethods doc has a nice section on "auto generated methods" -- I didn't notice that it's the argument to :belongs_to that defines the method name and not :foreign_key, i.e. it generates:

   WeatherObservation#start_time rather than:    WeatherObservation#start_time_id

Good catch -- thanks.