Я пытаюсь отслеживать спутники GPS, когда они пересекают небо. Я получаю сообщения «SKY» каждые 5 секунд, содержащие данные о местоположении и уровне сигнала для каждого видимого в данный момент спутника. База данных содержит таблицы для «небес», «sats», «треков» и «точек». Идея состоит в том, что каждое полученное небо будет добавлять точку местоположения к каждой дорожке его спутника. Схема ...
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
Определения модели: ...
class Sky < ApplicationRecord
include ActionView::Helpers::NumberHelper
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
При получении сообщения о небе проверяется предыдущий небесное сообщение, чтобы увидеть, какой из его спутников также существовал там. Для найденных, точка просто добавляется в таблицу треков этого спутника. Если спутник не был виден на последнем небе, создается новая запись спутника, и его местоположение «точка» добавляется к дорожке нового спутника.
Обратите внимание, что запись точки имеет внешние ключи для обеих дорожек. и небо записывает.
Первоначально у меня все это работало, но я создавал запись неба, затем создавал записи спутниковой записи / дорожки (если необходимо), а затем сохранял точку. Сбой питания при обработке сообщения неба заставил базу данных содержать спутниковую дорожку без точек. Я понимаю, что мог бы просто окружить всю эту обработку блоком транзакций, но подумал, что более чистым решением будет создание всех различных компонентов для небесного сообщения в памяти и по завершении сохранение всей партии с помощью одного new_sky.save.
Но, как ни старайся, мне кажется, я не могу получить правильную комбинацию reverse_of, nested_attributes и других атрибутов определения, чтобы успешно сохранить результаты. Со всем, что настроено, как указано здесь, в настоящее время я получаю следующее при обработке первого спутника в первом полученном сообщении неба ...
D, [2020-05-03 10:37:32.410281000 -0500 CDT#83744] DEBUG -- GpsComms: ************* This sat (#8) not found in previous SKY, create new *************
E, [2020-05-03 10:37:32.436055000 -0500 CDT#83744] ERROR -- GpsComms: Sat Processing Failed
E, [2020-05-03 10:37:32.436454000 -0500 CDT#83744] ERROR -- GpsComms: {:Rescue=>"#<ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)>"}
E, [2020-05-03 10:37:32.436786000 -0500 CDT#83744] ERROR -- GpsComms: Could not find the inverse association for track (:point in Track) - (ActiveRecord::InverseOfAssociationNotFoundError)
С другими комбинациями опций (reverse_of :, необязательно :, et c) Я получаю сообщения об ошибках, указывающие, что различные объекты должны существовать.
Я думаю, что я близко. Я надеюсь, что кто-нибудь может найти правильную комбинацию определений, чтобы заставить это работать.
Спасибо за любую помощь,
ОБНОВЛЕНИЕ: Я полагал, что ошибка выше ("Не удалось найти при попытке сохранить новый объект неба была сгенерирована обратная связь для трека (: точка в треке) "). Он на самом деле генерируется, когда новая точка добавляется в коллекцию точек.
На данный момент я создал новое небо с
sky = Sky.new (параметры)
Спутник создан с
sat = sky.sats.build (параметры)
Трек с
track = sat.build_track ( empty )
Теперь я могу сделать либо
new_point = sat.track.points. build (параметры)
или
sat.track.points << Point.new (параметры) </p>
для генерации обратного ассо c ошибка.
Надеюсь, что это поможет!
ОБНОВЛЕНИЕ: Благодаря предложению Eyselandi c ниже - вот исполняемый файл. Ошибка в последней строке с ошибкой «обратная связь».
# Activate the gem you are reporting the issue against.
gem 'activerecord', '6.0.0'
require 'active_record'
require 'minitest/autorun'
require 'logger'
# Ensure backward compatibility with Minitest 4
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(
adapter: 'postgresql',
database: 'database_name',
username: 'username',
password: 'password'
)
ActiveRecord::Base.logger = Logger.new(STDOUT)
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
ActiveRecord::Schema.define do
create_table "points", force: :cascade do |t|
t.bigint "track_id"
t.integer "az"
t.integer "el"
t.integer "ss"
t.boolean "used"
t.boolean "duplicate"
t.integer "PRN"
t.bigint "sky_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["PRN"], name: "index_points_on_PRN"
t.index ["created_at"], name: "index_points_on_created_at"
t.index ["sky_id"], name: "index_points_on_sky_id"
t.index ["track_id"], name: "index_points_on_track_id"
end
create_table "sats", force: :cascade do |t|
t.integer "PRN"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["PRN"], name: "index_sats_on_PRN"
end
create_table "sats_skies", id: false, force: :cascade do |t|
t.bigint "sky_id", null: false
t.bigint "sat_id", null: false
t.index ["sat_id", "sky_id"], name: "index_sats_skies_on_sat_id_and_sky_id"
t.index ["sky_id", "sat_id"], name: "index_sats_skies_on_sky_id_and_sat_id"
end
create_table "skies", force: :cascade do |t|
t.string "klass"
t.string "tag"
t.string "device"
t.float "time"
t.float "xdop"
t.float "ydop"
t.float "vdop"
t.float "tdop"
t.float "hdop"
t.float "pdop"
t.float "gdop"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["created_at"], name: "index_skies_on_created_at"
end
create_table "tracks", force: :cascade do |t|
t.bigint "sat_id"
t.index ["sat_id"], name: "index_tracks_on_sat_id"
end
end
class Sky < ApplicationRecord
has_and_belongs_to_many :sats, inverse_of: :sky, dependent: :destroy
has_many :points, inverse_of: :sky
accepts_nested_attributes_for :sats, allow_destroy: true
accepts_nested_attributes_for :points, allow_destroy: true
end
class Sat < ApplicationRecord
has_and_belongs_to_many :skies, inverse_of: :sat, autosave: true
has_one :track, inverse_of: :sat
accepts_nested_attributes_for :skies, allow_destroy: true
accepts_nested_attributes_for :track, allow_destroy: true
end
class Track < ApplicationRecord
has_many :points, inverse_of: :track
belongs_to :sat, inverse_of: :track
accepts_nested_attributes_for :points, allow_destroy: true
end
class Point < ApplicationRecord
belongs_to :sky, inverse_of: :point #, optional: true
belongs_to :track, inverse_of: :point #, optional: true
end
class BugTest < Minitest::Test
def test_association_stuff
sky_attr= {
:klass=>"SKY",
:device=>"/dev/ttyAMA0",
:xdop=>0.62,
:ydop=>0.89,
:vdop=>0.94,
:tdop=>1.15,
:hdop=>1.23,
:gdop=>2.28,
:pdop=>1.55
}
sky = Sky.new(sky_attr)
sat = sky.sats.build(:PRN=>7)
track = sat.build_track
point_attr= {
:PRN=>7,
:el=>61,
:az=>340,
:ss=>21,
:used=>true,
# :sky_id=>nil,
:duplicate=>false
}
point=sat.track.points.build( point_attr)
sky.save
end
end
Ошибка:
Error:
BugTest#test_association_stuff:
ActiveRecord::InverseOfAssociationNotFoundError: Could not find the inverse association for track (:point in Track)
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:240:in `check_validity_of_inverse!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:474:in `check_validity!'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:43:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations.rb:237:in `association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:286:in `inverse_association_for'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:107:in `set_inverse_instance'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:187:in `initialize_attributes'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:318:in `block in build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/core.rb:328:in `initialize'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/inheritance.rb:70:in `new'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/reflection.rb:158:in `build_association'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/association.rb:317:in `build_record'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_association.rb:108:in `build'
/Users/sjf/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/associations/collection_proxy.rb:316:in `build'
active_record_gem.rb:136:in `test_association_stuff'