Why am I getting a "NameError: uninitialized constant" using has_many :through in Ruby

Why am I getting a "NameError: uninitialized constant" using has_many :through in Ruby

我是 Ruby 的初学者,一直在尝试使用 has_many :through 关联将 3 个模型连接在一起。首先,我有一个 Person 模型、一个 Subscription 模型和一个 SubscriptionDetail 模型。

基本上,一个人可以通过订阅详情拥有多个订阅,同样,一个订阅可以通过订阅详情拥有多人。我使用的模型是:

在person.rb中:

class Person < ActiveRecord::Base
    belongs_to :institution
    has_many :subscription_details
    has_many :subscriptions, through: :subscription_details
end

在subscription.rb中:

class Subscription < ActiveRecord::Base
    belongs_to :product
    has_many :subscription_details
    has_many :people, through: :subscription_details
end

在subscription_detail.rb中:

class SubscriptionDetail < ActiveRecord::Base
    belongs_to :person
    belongs_to :subscription
end

相关的迁移是:

class CreatePeopleTable < ActiveRecord::Migration[5.0]
  def change
    create_table :people do |t|
        t.string :name, null:false
        t.string :email, null:false
        t.belongs_to :institution, index: true
        t.boolean :removed, :default => false
        t.timestamps
    end
  end
end

class CreateSubscriptionsTable < ActiveRecord::Migration[5.0]
  def change
    create_table :subscriptions do |t|
        t.string :name, null:false
        t.belongs_to :product, index: true
    end
  end
end

class CreateSubscriptionDetailsTable < ActiveRecord::Migration[5.0]
  def change
    create_table :subscription_details do |t|
        t.belongs_to :subscription, index:true
        t.belongs_to :person, index:true
        t.boolean :trial, :default => true
        t.string :mailing_preference, :default => "Cc"
        t.datetime :trial_start
        t.datetime :trial_end
    end
  end
end

创建一个人时,我设置了一个表单,通过同一个表单(使用复选框)向该人添加多个订阅 - 我将这些收集到一个名为 "subscriptions" 的数组中。订阅是使用另一种形式预先创建的。我使用以下代码(对 has_many through additional attributes 中的内容稍作修改)来创建此人:

info = {
    name: name,
    email: email,
    institution_id: institution.id
}

person = Person.create(info)
person.save

subscriptions.each do |each_subscription|
    person.subscription_details.create(
        :subscription => each_subscription,
        :trial_start => trial_start,
        :trial_end => trial_end
    )
end

但我总是得到以下错误:

NameError at /institutions/1/add_person
uninitialized constant Person::SubscriptionDetail

更新: 它在 person.subscription_details.create( 行抛出异常。

当控制台中 运行 相同的代码时,我得到 NameError: uninitialized constant Person::SubscriptionDetail from C:/Ruby22-x64/lib/ruby/gems/2.2.0/gems/activerecord-5.0.1/li‌​b/active_record/inhe‌​ritance.rb:152:in 'compute_type'

更新 2: 我应该注意,在检查 Postgres 中的数据库时,它在 people table 中创建了人,但没有在中创建相关的订阅详细信息subscription_detailstable

我检查了多个模型文件、关联,甚至检查了拼写错误,尝试在模型中使用 :class_name 属性,我在没有 person.save 的情况下尝试过,最后 2小时谷歌搜索这个,但我无法弄清楚为什么这是失败的。

更新

窗体视图 (people/new.erb)

<form action="/institutions/<%= @institution.id %>/add_person" method="post">
    <table>
        <tr>
            <th><label for="name">Name</label></th>
            <td><input type="text" id="name" name="person[name]" placeholder="Name"></td>
        </tr>
        <tr>
            <th><label for="email">E-mail</label></th>
            <td><input type="text" id="email" name="person[email]" placeholder="E-mail"></td>
        </tr>
        <tr>
            <th><label for="institution">Institution</label></th>
            <td><input type="text" id="institution" name="person[institution]" placeholder="<%= @institution.name %>" value="<%= @institution.name %>"></td>
        </tr>
        <tr>
            <th>Subscriptions</th> 
            <td>
                <% @subscriptions.each do |subscription| %>
                    <label><input type="checkbox" name="person[subscriptions][]" value="<%= subscription.id %>"><%= subscription.name %></label><br>
                <% end %>
            </td>
        </tr>
        <tr>
            <th><label for="trial-start">Trial-start Date</label></th>
            <td>
                <input type="text" id="trial-start" name="person[trial][start]" placeholder="DD-MM-YYYY">
            </td>
        </tr>
        <tr>
            <th><label for="trial-end">Trial-end Date</label></th>
            <td>
                <input type="text" id="trial-end" name="person[trial][end]" placeholder="DD-MM-YYYY">
            </td>
        </tr>
    </table>
    <input class="button" type="submit" value="Add Person">
</form>

在 Rails 4.2 中,您的 SubscriptionDetails 迁移看起来像这样:

class CreateSubscriptionDetailsTable < ActiveRecord::Migration
  def change
    create_table :subscription_details do |t|
      t.belongs_to :subscription, index: true, foreign_key: true, null: false
      t.belongs_to :person, index: true, foreign_key: true, null: false
      t.boolean :trial, default: true
      t.string :mailing_preference, default: "Cc"
      t.datetime :trial_start
      t.datetime :trial_end
    end

    add_index :subscription_details, ["subscription_id", "person_id"], unique: true
  end
end

不确定 5.0 中进行了哪些更改,但可能值得添加索引和外键约束以查看是否可以解决问题。当然,您需要回滚迁移并再次 运行 它们。

嗯,现在我觉得我真的很愚蠢。我向所有可能在这里浪费时间的人道歉,并真诚地感谢你们付出的所有努力。

但这是我的错。我忘了检查我的 config.ru 文件。我通过将以下行添加到我的 config.ru 文件中解决了这个问题:

require './models/subscription_detail'

这就是为什么我的应用程序看不到 SubscriptionDetail 模型的原因。我只是回答这个问题,以防它能帮助任何犯同样错误的人。

再次感谢所有answered/commented的人。