2016-12-05 3 views
0

У меня есть два класса: Restream и Channel. Канал может иметь много передышек, и релакс может принадлежать многим каналам. Тем не менее, мне нужно Restream также для хранения active_channel - идентификатор канала, который его использует сейчас.HABTM и ошибка модели has_one

class Restream < ActiveRecord::Base 
    has_one :active_channel, class_name: 'Channel' 

    has_and_belongs_to_many :channels 
    ... 
end 

class Channel < ActiveRecord::Base 
    has_and_belongs_to_many :restreams 
    ... 

end 

миграции я написал для добавления active_channel:

add_column :restreams, :active_channel, :integer, index: true 
add_foreign_key :restreams, :channels, column: :active_channel 

Тем не менее каждый раз, когда я бегу rails c и вызвать Restream.last я получаю это:

irb(main):002:0> Restream.last 
    Restream Load (1.2ms) SELECT "restreams".* FROM "restreams" ORDER BY "restreams"."id" DESC LIMIT 1 
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column channels.restream_id does not exist 
LINE 1: SELECT "channels".* FROM "channels" WHERE "channels"."restr... 
               ^
: SELECT "channels".* FROM "channels" WHERE "channels"."restream_id" = $1 ORDER BY "channels"."name" ASC LIMIT 1 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:637:in `prepare' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:637:in `prepare_statement' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:596:in `exec_cache' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql_adapter.rb:585:in `execute_and_clear' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:160:in `exec_query' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:355:in `select' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/database_statements.rb:32:in `select_all' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/connection_adapters/abstract/query_cache.rb:70:in `select_all' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/querying.rb:39:in `find_by_sql' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/relation.rb:639:in `exec_queries' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/association_relation.rb:32:in `exec_queries' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/relation.rb:515:in `load' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/relation.rb:243:in `to_a' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/associations/singular_association.rb:42:in `get_records' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/associations/singular_association.rb:57:in `find_target' 
    from /bundler_cache/gems/activerecord-4.2.5.1/lib/active_record/associations/association.rb:138:in `load_target' 
... 4 levels... 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/ext/active_record.rb:45:in `each' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/ext/active_record.rb:45:in `inject' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/ext/active_record.rb:45:in `awesome_active_record_instance' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/formatter.rb:26:in `format' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/inspector.rb:137:in `unnested' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/inspector.rb:104:in `awesome' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/core_ext/kernel.rb:10:in `ai' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/core_ext/kernel.rb:20:in `ap' 
    from /bundler_cache/gems/awesome_print-1.6.1/lib/awesome_print/inspector.rb:31:in `output_value' 
    from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/console.rb:110:in `start' 
    from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/console.rb:9:in `start' 
    from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/commands_tasks.rb:68:in `console' 
    from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!' 
    from /bundler_cache/gems/railties-4.2.5.1/lib/rails/commands.rb:17:in `<top (required)>' 
    from bin/rails:4:in `require' 
    from bin/rails:4:in `<main>' 

я узнал, что он не на заявлении SELECT "channels".* FROM "channels" WHERE "channels"."restream_id" = $1 ORDER BY "channels"."name" ASC LIMIT 1

Что я делаю Неправильно? Thanx

ответ

0

Проблема здесь в том, что имя столбца должно быть restream_id не restreams.

И что вы добавили столбец и внешнюю ссылку на Restream для Channel, но имеет один будет означать, что Channel принадлежит Restream, что другой путь вокруг из вашего кода.

Я думаю, вы можете легко исправить это, указав, что Restream принадлежит к Channel.

class Restream < ActiveRecord::Base 
    belongs_to :active_channel, class_name: 'Channel' 
    has_and_belongs_to_many :channels 
    ... 
end 

class Channel < ActiveRecord::Base 
    has_and_belongs_to_many :restreams 
    ... 
end 

Это решение предполагает, что вы хотите сохранить «активный» канал на restream, то есть канал может иметь много/один restream (ы).

Если вы хотите по-другому, вам придется переключать весь код, откат вашего БД меняет вашу миграцию, тогда все должно работать.

+0

Да, изменив 'has_one'' '' '' '' '' '' решил. Я также думаю, что это звучит лучше с 'belongs_to' =) Также я вернулся к направляющим rails и понял, в чем была проблема, но теперь попытайтесь понять, почему' has_one' создает 'id', как это. Я бы ожидал, что создание id похоже на 'own_to' на самом деле. – Ngoral

+0

@Ngoral, 'принадлежит_то',' has_one', 'has_many' и' has_and_belongs_to_many' управляет только запросами, используемыми для извлечения записей. Но фактическое создание столбцов в базе данных зависит от выполняемой миграции. И 'has_one' является особенным, вы можете сделать его' has_many', просто изменив код, так как это 'own_to', что действительно имеет значение и содержит внешние отношения.Единственная разница между 'has_many' и' has_one' заключается в том, что 'has_one' выполняет запрос SELECT ... LIMIT 1, который ограничен одной записью. Но обе используют для 'request_to' другой модели. – fbelanger

0

Вы перепутали имя столбца. В соглашениях ActiveRecord столбцы внешнего ключа должны заканчиваться _id.

Если вы еще не совершили плохую миграцию, вы можете просто вернуть ее обратно с помощью rake db:rollback и исправить миграцию.

add_column :restreams, :active_channel_id, :integer, index: true 
add_foreign_key :restreams, :channels, column: :active_channel_id 

В противном случае вам необходимо создать новую миграцию, которая переименовывает столбец.

remove_foreign_key(:restreams, :channels, column: :active_channel) 
remove_index(:restreams, :active_channel_id) 
rename_column(:restreams, :active_channel, :active_channel_id) 
add_foreign_key(:restreams, :channels, column: :active_channel_id) 
add_index(:restreams, :active_channel_id) 

И вы должны использовать belongs_to и не has_one отношений в качестве последнего ставит ключевой столбец иностранного на другой стороне отношений.

class Restream < ActiveRecord::Base 
    # stores the relation as `restreams.active_channel_id` 
    belongs_to :active_channel, class_name: 'Channel', 
           optional: true 

    has_and_belongs_to_many :channels 
    ... 
end 

class Channel < ActiveRecord::Base 
    # or has_one 
    has_many :active_restreams, class_name: 'Restream', 
           foreign_key: 'active_channel_id' 
    has_and_belongs_to_many :restreams 
    ... 

end 
+0

Вы правы в названии столбца. Но 'has_one: active_channel' по-прежнему будет пытаться найти канал, запросив« каналы ».« Restream_id », что не то, что делает миграция. Добавление столбца в restrem означает, что оно 'принадлежит_то'. – fbelanger

+0

Просто отредактировал ответ с объяснением, что аферу следует использовать 'принадлежит_то' – max

+0

@max На самом деле теперь он работает без изменения миграции, но только путем замены' has_one' на 'own_to' – Ngoral

Смежные вопросы