1

私は Rails の初心者で (Hartl のチュートリアルを終えたばかりです)、これまでに経験したものよりも少し複雑に見えるいくつかの種類の関連付けに問題があります。問題の解決策を求めてGoogleとstackoverflowを閲覧してきましたが、関連する回答がたくさん見つかりましたが、問題を解決する方法がわかりません。

基本的に私がやろうとしているのは、次の関係を実装することです:

ER図

それについて調べた結果、私が思いついたのは次のとおりです。

モデル

# models/user.rb
class User < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :email …

  has_many :speak, :class_name => "Speaks"
  has_many :speaks, :through => :speak, :source => :language

  has_many :want_to_learn, :class_name => "WantsToLearn"
  has_many :wants_to_learn, :through => :want_to_learn, :source => :language
  …

end

# models/language.rb
class Language < ActiveRecord::Base
  attr_accessible :iso_639_1_code, :name_en, :name_fr, :name_pt

  has_many :speak, :class_name => "Speaks"
  has_many :users_who_speak, :through => :speak, :source => :user

  has_many :want_to_learn, :class_name => "WantsToLearn"
  has_many :users_who_want_to_learn, :through => :wants_to_learn, :source => :user
end

# models/speaks.rb
class Speaks < ActiveRecord::Base
  set_table_name 'speak'
  attr_accessible :level, :language
  references :user
  references :language
end

# models/wants_to_learn.rb
class WantsToLearn < ActiveRecord::Base
  set_table_name 'want_to_learn'
  attr_accessible :language
  references :user
  references :language
end

移行

# db/migrate/20130210153328_create_speak.rb
class CreateSpeak < ActiveRecord::Migration
  def change
    create_table :speak do |t|
      t.references :user
      t.references :language
      t.integer :level

      t.timestamps
    end
  end
  add_index :speak, :user
  add_index :speak, :language
end

# db/migrate/20130210153342_create_want_to_learn.rb
class CreateWantToLearn < ActiveRecord::Migration
  def change
    create_table :want_to_learn do |t|
      t.references :user
      t.references :language

      t.timestamps
    end
  end
  add_index :want_to_learn, :user
  add_index :want_to_learn, :language
end

これを実行して実行しようとするとrake:db migrate、次のエラーが発生します。

-- add_index(:speak, :user)
rake aborted!
An error has occurred, this and all later migrations canceled:

PG::Error: ERROR:  relation "speak" does not exist
: CREATE  INDEX "index_speak_on_user" ON "speak" ("user")
...

行をコメントアウトするとadd_index、移行は正常に実行されますが、ユーザーから「話す」関係を作成できません。たとえば、次のように実行すると:

> john = User.new(first_name: "John", last_name: "Doe", email: "john@doe.com"...)

> john.speaks.create!(level: '6', language: '139')

私は得る:

NoMethodError: undefined method `references' for #<Class:0x007ff14c1771a0>

すべての「参照」を「belongs_to」やその他いくつかのものに置き換えようとしましたが、その多くは覚えていませんが、役に立ちませんでした。これにより、次のようないくつかの疑問が頭に浮かびました。

• "references" は本当に "belongs_to" と同じですか? モデルのコンテキストでも?「参照」が移行で使用されているのを見たことがありますが、モデルは使用されていません。

• "class_name" を正しく使用していますか? 本当に自信がありません。これは、私が読んだすべての後に最も理にかなっているものですが、このような関連付けでカスタマイズの例を見たことがありません.

• これらのインデックスを追加することの何が問題になっていますか?

さて、ここでのエチケットが何であるかはわかりませんが、私の最後の質問は次のとおりです。

これをすべて適切に行うにはどうすればよいですか??

前もって感謝します!

------編集------

キーワード「参照」を「belongs_to」に置き換えました。インデックスに関する移行エラーはまったく同じです。インデックス作成行にコメントを付けたら、移行を実行し、ユーザーを作成してからコマンドを試してください

> john.speaks.create!(level: 6, language: 139)

エラーは次のとおりです。

ActiveModel::MassAssignmentSecurity::Error:
Can't mass-assign protected attributes: level, language

ラインにもかかわらずattr_accessible :level, :language

4

2 に答える 2

1

わかった。私は最終的にすべてを機能させることができましたが、コミュニティが質問に答えずに放棄することはあまり建設的ではないと思います. 私のコードは今では完全に機能し、ネストされたフォームを許可するために必要な追加が含まれています。外観は次のとおりです。

モデル

# models/user.rb
class User < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :email, ... ,
  :speaks_attributes, :wants_to_learn_attributes
  # These last two attributes are necessary for nested forms

  has_many :speaks, :class_name => "Speaks", :dependent => :destroy
  accepts_nested_attributes_for :speaks, :allow_destroy => true # this one too
  has_many :speaks_languages, :through => :speaks, :source => :language

  has_many :wants_to_learn, :class_name => "WantsToLearn", :dependent => :destroy
  accepts_nested_attributes_for :wants_to_learn, :allow_destroy => true # and this one too
  has_many :wants_to_learn_languages, :through => :wants_to_learn, :source => :language
  .
  .
  .

end

# models/language.rb
class Language < ActiveRecord::Base
  attr_accessible :iso_639_1_code, :name_en, :name_fr, :name_pt

  has_many :speak, :class_name => "Speaks"
  has_many :users_who_speak, :through => :speak, :source => :user

  has_many :want_to_learn, :class_name => "WantsToLearn"
  has_many :users_who_want_to_learn, :through => :want_to_learn, :source => :user
end

# models/speaks.rb
class Speaks < ActiveRecord::Base
  set_table_name 'speak'
  attr_accessible :language, :language_id, :level
  belongs_to :user
  belongs_to :language
end

# models/wants_to_learn.rb
class WantsToLearn < ActiveRecord::Base
  set_table_name 'want_to_learn'
  attr_accessible :language, :language_id
  belongs_to :user
  belongs_to :language
end

移行

# db/migrate/20130210153328_create_speak.rb
class CreateSpeak < ActiveRecord::Migration
  def change
    create_table :speak, :id => false do |t|
      t.belongs_to :user
      t.belongs_to :language
      t.integer :level

      t.timestamps
    end
    add_index :speak, :user_id
    add_index :speak, :language_id
  end
end


# db/migrate/20130210153342_create_want_to_learn.rb
class CreateWantToLearn < ActiveRecord::Migration
  def change
    create_table :want_to_learn, :id => false do |t|
      t.belongs_to :user
      t.belongs_to :language

      t.timestamps
    end
    add_index :want_to_learn, :user_id
    add_index :want_to_learn, :language_id
  end
end

移行では、「add_index」行を「def change」ブロックの内側に配置しました。前回、私は愚かで気を散らして外に残し、「user」と「language」をそれぞれ「user_id」と「language_id」に変更しました。それはそれを修正しました。

これで user を作成し、次のコマンドarielを実行してポルトガル語とフランス語を話せるようにします。

> ariel.speaks.create!(language_id: 129, level: 6)
> ariel.speaks.create!(language_id: 50, level: 4)

ariel次に、次のコマンドを実行して、「speak」テーブルに関連付けられているエントリを取得できます。

> ariel.speaks
=> [#<Speaks id: 1, user_id: 1, language_id: 129, level: 6, created_at: "2013-02-25 19:30:01", updated_at: "2013-02-25 19:30:01">, #<Speaks id: 4, user_id: 1, la
nguage_id: 50, level: 4, created_at: "2013-02-26 12:37:34", updated_at: "2013-02-26 12:37:34">]

そして、次を実行して「言語」テーブルのエントリを取得します。

> ariel.speaks_languages
 => [#<Language id: 50, iso_639_1_code: "fr", name_en: "French", name_fr: "français\n", name_pt: nil>, #<Language id: 129, iso_639_1_code: "pt", name_en: "Portugu
ese", name_fr: "portugais\n", name_pt: nil>]

この手順は、wants_to_learn 関連付けの場合と似ています。

于 2013-02-26T13:10:05.187 に答える
1

私は Rails での references キーワードは初めてですが、Rails ガイドの移行では見られますが、クラスでは見られないため、クラスでは使用しないでください。

したがって、begs_to はクラスで使用され、参照は移行で使用されるため、belongs_to とは異なります。

また、インデックスを作成するときに、移行がクラス内の関連付けを気にすることも初めてです。

于 2013-02-23T21:35:23.137 に答える