Rails 夹具创建顺序问题

发布于 2024-10-16 20:05:45 字数 1461 浏览 0 评论 0原文

我正在阅读 Sitepoint 的《Simply Rails》一书,并给出了这些模型:

story.rb

class Story < ActiveRecord::Base
    validates_presence_of :name, :link
    has_many :votes do
        def latest
            find :all, :order => 'id DESC', :limit => 3
        end
    end

    def to_param
        "#{id}-#{name.gsub(/\W/, '-').downcase}"
    end
end

vote.rb

class Vote < ActiveRecord::Base
    belongs_to :story
end

并给出了这个固定装置

Stories.yml

one:
  name: MyString
  link: MyString

two:
  name: MyString2
  link: MyString2

votes.yml

one:
  story: one

two:
  story: one

,这些测试失败了:

story_test.rb

def test_should_have_a_votes_association
    assert_equal [votes(:one),votes(:two)], stories(:one).votes
  end

def test_should_return_highest_vote_id_first
    assert_equal votes(:two), stories(:one).votes.latest.first
  end

但是,如果我颠倒故事的顺序,对于第一个断言并为第一个断言提供第一次投票,它通过了

story_test.rb

def test_should_have_a_votes_association
    assert_equal [votes(:two),votes(:one)], stories(:one).votes
  end

  def test_should_return_highest_vote_id_first
    assert_equal votes(:one), stories(:one).votes.latest.first
  end

我复制了书中的所有内容,并且没有看到关于此的勘误表。我的第一个结论是,该装置正在按照宣布的方式从下到上创建记录,但这没有任何意义

编辑:我正在使用在 RVM 中运行的 Rails 2.9

I am reading the book Simply Rails by Sitepoint and given these models:

story.rb

class Story < ActiveRecord::Base
    validates_presence_of :name, :link
    has_many :votes do
        def latest
            find :all, :order => 'id DESC', :limit => 3
        end
    end

    def to_param
        "#{id}-#{name.gsub(/\W/, '-').downcase}"
    end
end

vote.rb

class Vote < ActiveRecord::Base
    belongs_to :story
end

and given this fixtures

stories.yml

one:
  name: MyString
  link: MyString

two:
  name: MyString2
  link: MyString2

votes.yml

one:
  story: one

two:
  story: one

these tests fail:

story_test.rb

def test_should_have_a_votes_association
    assert_equal [votes(:one),votes(:two)], stories(:one).votes
  end

def test_should_return_highest_vote_id_first
    assert_equal votes(:two), stories(:one).votes.latest.first
  end

however, if I reverse the order of the stories, for the first assertion and provide the first vote for the first assertion, it passes

story_test.rb

def test_should_have_a_votes_association
    assert_equal [votes(:two),votes(:one)], stories(:one).votes
  end

  def test_should_return_highest_vote_id_first
    assert_equal votes(:one), stories(:one).votes.latest.first
  end

I copied everything as it is in the book and have not seen an errata about this. My first conclusion was that the fixture is creating the records from bottom to top as it was declared, but that doesn't make any point

any ideas?

EDIT: I am using Rails 2.9 running in an RVM

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏了南城 2024-10-23 20:05:45

您的装置没有像您期望的那样获得 ID 1、2、3 等 - 当您添加装置时,它们会根据(我认为)表名称和装置名称的哈希值获得 ID。对于我们人类来说,它们只是看起来像随机数。

Rails 这样做是为了让您可以轻松地通过名称引用其他装置。例如,灯具

#parents.yml
vladimir:
  name: Vladimir Ilyich Lenin

#children.yml
joseph:
  name: Joseph Vissarionovich Stalin
  parent: vladimir

实际上显示在您的数据库中,特别是

#parents.yml
vladimir:
  id: <%= fixture_hash('parents', 'vladimir') %>
  name: Vladimir Ilyich Lenin

#children.yml
joseph:
  id: <%= fixture_hash('children', 'joseph') %>
  name: Joseph Vissarionovich Stalin
  parent_id: <%= fixture_hash('parents', 'vladimir') %>

请注意从 parent: vladimirparent_id: <%= ... %> 的扩展子模型 - 这就是 Rails 处理装置之间关系的方式。

这个故事的寓意是:不要指望你的装置按任何特定的顺序排列,也不要指望 :order =>; :id 在测试中为您提供有意义的结果。使用results.member? objX 重复而不是results == [obj1, obj2, ...]。如果您需要固定 ID,请自行将其硬编码。

希望这有帮助!

PS:列宁和斯大林实际上没有关系。

Your fixtures aren't getting IDs 1, 2, 3, etc. like you'd expect - when you add fixtures, they get IDs based (I think) on a hash of the table name and the fixture name. To us humans, they just look like random numbers.

Rails does this so you can refer to other fixtures by name easily. For example, the fixtures

#parents.yml
vladimir:
  name: Vladimir Ilyich Lenin

#children.yml
joseph:
  name: Joseph Vissarionovich Stalin
  parent: vladimir

actually show up in your database like

#parents.yml
vladimir:
  id: <%= fixture_hash('parents', 'vladimir') %>
  name: Vladimir Ilyich Lenin

#children.yml
joseph:
  id: <%= fixture_hash('children', 'joseph') %>
  name: Joseph Vissarionovich Stalin
  parent_id: <%= fixture_hash('parents', 'vladimir') %>

Note in particular the expansion from parent: vladimir to parent_id: <%= ... %> in the child model - this is how Rails handles relations between fixtures.

Moral of the story: Don't count on your fixtures being in any particular order, and don't count on :order => :id giving you meaningful results in tests. Use results.member? objX repeatedly instead of results == [obj1, obj2, ...]. And if you need fixed IDs, hard-code them in yourself.

Hope this helps!

PS: Lenin and Stalin weren't actually related.

萌梦深 2024-10-23 20:05:45

Xavier Holt 已经给出了主要答案,但还想提一下,可以强制 Rails 按特定顺序读取固定装置。

默认情况下,rails 会分配自己的 ID,但您可以利用 YAML omap 规范来指定有序映射。

# countries.yml
--- !omap
- netherlands:
    id:         1
    title:      Kingdom of Netherlands
- canada:
    id:         2
    title:      Canada

由于您强制执行顺序,因此您还必须自己手动指定 ID,如上所示。

我也不确定这部分,但我认为一旦您承诺覆盖默认的 Rails 生成的 ID 并使用您自己的 ID,您就必须对所有下游引用执行相同的操作。

在上面的示例中,假设每个国家/地区可以有多个领导者,您需要执行类似的操作

# leaders.yml
netherlands-leader:
  country_id: 1   #you have to specify this now!
  name: Willem-Alexander

您需要手动指定引用先前模型(国家/地区)的 id

Xavier Holt already gave the main answer, but wanted to also mention that it is possible to force rails to read in fixtures in a certain order.

By default rails assigns its own IDs, but you can leverage the YAML omap specification to specify an ordered mapping

# countries.yml
--- !omap
- netherlands:
    id:         1
    title:      Kingdom of Netherlands
- canada:
    id:         2
    title:      Canada

Since you are forcing the order, you have to also specify the ID yourself manually, as shown above.

Also I'm not sure about this part, but I think once you commit to overriding the default rails generated ID and use your own, you have to do the same for all downstream references.

In the above example, suppose each country can have multiple leaders, you would have do something like

# leaders.yml
netherlands-leader:
  country_id: 1   #you have to specify this now!
  name: Willem-Alexander

You need to manually specify the id that refers to the previous Model (Countries)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文