2016-12-05 4 views
0

私は2つのクラス:RestreamChannelを持っています。チャネルには多くの再ストリームがあり、再ストリームは多くのチャネルに属している可能性があります。しかし、Restreamにはactive_channel - これを使用しているチャンネルのIDも格納する必要があります。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であることです。

そして、あなたはChannelためRestreamに列と外国の参照を追加しましたが、1はChannelがあなたのコードから他の方法で回避されている、Restreamに属することを意味しているという。

RestreamChannelに属していると簡単に言えます。

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 

このソリューションは、「アクティブな」チャネルをリストライムに保存することを前提としています。つまり、1つのチャネルに複数の/ 1つのリストリームを含めることができます。

逆の場合は、すべてのコードを切り替えて、DBをロールバックして移行を行う必要があります。すべてが機能するはずです。

+0

はい、「has_one」を「belongs_to」に変更すると解決しました。 'belongs_to' =)でもうまくいくと思う。また、レールガイドに戻って問題があったのだが、今は' has_one'がなぜこのような 'id'を作るのか理解しようとする。私は実際には 'belongs_to'のようなidを作成すると期待しています。 – Ngoral

+0

@Ngoral、 'belongs_to'、' has_one'、 'has_many'および' has_and_belongs_to_many'は、レコードを取得するために使用されるクエリのみを制御します。しかし、データベース内の実際の列の作成は、実行された移行までです。 'has_one'は特別です。コードを変更するだけで' has_many'にすることができます。なぜなら、本当に重要で外国関係を保持する 'belongs_to'だからです。'has_many'と' has_one'の唯一の違いは、 'has_one'が単一のレコードに限定された' SELECT ... LIMIT 1'クエリを実行することです。しかし、両方ともクエリのために他のモデルの 'belongs_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に列を追加すると、それは 'belongs_to'を意味します。 – fbelanger

+0

askerが 'belongs_to'を使用しているという説明で答えを編集しました – max

+0

@max実際には、マイグレーションを変更せずに' has_one'を 'belongs_to'に置き換えるだけで動作します。 – Ngoral