【问题标题】:Why am I getting a "NameError: uninitialized constant" using has_many :through in Ruby为什么我在 Ruby 中使用 has_many :through 得到“NameError:未初始化的常量”
【发布时间】:2017-01-24 18:09:31
【问题描述】:

我是 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

在订阅.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

创建一个人时,我设置了一个表单,通过同一个表单(使用复选框)向该人添加多个订阅 - 我将这些收集到一个名为“订阅”的数组中。订阅是使用另一种形式预先创建的。我使用以下代码(对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 表中创建了人员,但在 subscription_details 表中没有创建相关的订阅详细信息

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

更新

表单视图(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>

【问题讨论】:

  • 第一:我不知道你为什么会收到这个错误。我会对如何定义路由、如何命名模型和控制器以及如何定义表单以开始调查感兴趣。我在这里使用模型和关联模仿了您的设置,并让事情正常工作。你在用accepts_nested_attributes_for吗?我有更多的想法,但没有足够的字符 - 你能在你的问题中包含你的表单、控制器和模型代码吗?然后我也许可以尝试一下答案。
  • @wendybeth 哇,好吧,显然我更像是一个初学者,我认为 - 几乎没有听懂你说的。我的模型和控制器的命名空间是什么意思?我假设表单定义只是表单的结构?我从来没有听说过你所说的accepts_nested_attributes_for。另外,我上面的模型代码就是全部了,关于创建人的部分来自控制器 - 你还需要多少代码?
  • 只是一个旁注,但 Ruby/Rails 约定将本地迭代器变量称为 subscription 而不是 each_subscription。该变量仅代表一个订阅,每次迭代都会发生变化。
  • 不用担心。 :) 你的问题很好,所以我不会太担心。按命名空间:我看到你有'institutions/1/add_person',所以我想知道你的控制器是否设置了'app/controllers/institutions/people_controller'。此外,“add_person”不是默认的 Rails 路由——通常是“/people/new”——所以我想查看你的 config/routes.rb 文件。同时,如果您查看accepts_nested_attributes_for,我想您可能会在这里找到很多好东西来帮助您:api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/…
  • 另外,通过定义的表单,我只是指您用于创建表单的视图文件中的代码。

标签: ruby activerecord has-many-through


【解决方案1】:

在 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 中做了哪些更改,但可能值得添加索引和外键约束,看看它是否能解决问题。当然,您需要回滚迁移并再次运行它们。

【讨论】:

    【解决方案2】:

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

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

    require './models/subscription_detail'
    

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

    再次感谢所有回答/评论的人。

    【讨论】:

      猜你喜欢
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-28
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      相关资源
      最近更新 更多