【问题标题】:Creating fixture data for model using acts_as_taggable_on使用acts_as_taggable_on为模型创建夹具数据
【发布时间】:2010-11-01 17:05:30
【问题描述】:

我正在使用acts_as_taggable_on 插件为我的Framework 模型提供标记。我有 Rails 生成的功能测试,以及它使用的固定装置,我想扩展它们以添加一些标签,以便我可以测试标签搜索等。

我是否必须为taggingstag 表创建夹具并将它们加载到我的功能测试的顶部?如果是这样,我该怎么做?我还没有完全理解here 所描述的关系语法。是否可以在测试搜索行为之前获取Framework 实例并为其添加标签?或者如果我这样做,Rails 之神会击倒我吗?

【问题讨论】:

    标签: ruby-on-rails testing fixtures acts-as-taggable-on


    【解决方案1】:

    我也遇到了同样的问题。在进行了一些试验和错误之后,我想出了以下方法,通读有关固定装置、关联和@barnaclebarnes 对这个问题的回答的文档。

    我用 rails 4.2.0acts-as-taggable-on 3.5.0 做到了这一点。

    备注: 我之前的回答起到了作用,但有点古怪。在@David 向我指出一种更简洁的方式之后,我完全重写了它——完全省略了我的反复试验并坚持解决方案。

    一种促进更多轨道车载设施的方法

    @barnaclebarnes 解决方案将提供更多的自动化,但也意味着更多的 id 输入和簿记。所以我一直在寻找更简洁的方法。

    多态关系

    acts_as_taggable_on 使用名为taggable 的多态关系来实现标签与不​​同模型之间的关系。有关 polymorphic relations 的详细信息,请参阅有关关联的 rails 指南。

    高级夹具

    ActiveRecord::FixtureSet 的 ruby​​doc 描述了 ActiveRecord 的工作原理以及它对夹具关系的作用(章节 关联的标签引用):

    Active Record 反映fixture 的模型类,查找所有belongs_to 关联,并允许您为关联[...] 指定目标标签,而不是FK [...] 的目标ID。

    页面再往下一点,还有一些关于多态belongs_to的细节。

    这将允许像这样的标记夹具定义:

    tagging:
      taggable: foo (Klass)
      context: tags
      tag: bar
    

    命名空间夹具和模型

    ActiveRecord::TestFixtures 提供了一种方法来显式设置夹具的模型类,以防无法推断。 换句话说:您可以使用目录来命名固定装置并将它们与其命名空间模型相匹配。 要加载acts_as_taggable_on 的标签和标记的测试数据,我们可以将它们的fixture 放在子文件夹fixtures/acts_as_taggable_on/ 中(备注fixtures/ActsAsTaggableOn/ 也可以)

    把它们放在一起

    # models/item.rb
    class Item < ActiveRecord::Base
      acts_as_taggable_on
    end
    
    # fixtures/items.yml
    item_1: {}
    item_2: {}
    
    # fixtures/acts_as_taggable_on/tags.yml
    tag_1:
      name: tag_1
    tag_2:
      name: tag_2
    
    # fixtures/acts_as_taggable_on/taggings.yml
    tagging_1
      taggable: item_1 (Item)
      context: tags
      tag: tag_1
    

    如果您对 yaml 文件进行 erb 处理,则可以对可标记模型及其实例进行相当低的维护定义。

    【讨论】:

    • 在您的“有点古怪”的解决方案中,无需定义新模型。您可以将ActsAsTaggableOn 中的那些与set_fixture_class 一起使用。例如。在您的test_helper.rb 中,在fixtures :all 之后,添加set_fixture_class "tags" =&gt; ActsAsTaggableOn::Tagset_fixture_class "taggings" =&gt; ActsAsTaggableOn::Tagging。瞧!无需命名为TagTagging 的新模型。 hth
    • 感谢@David 为我指明了这个方向。根据文档 set_fixture_class 如果无法从夹具中推断出模型类,则可以使用,所以我想“它们是如何推断的?”。事实证明,您可以通过将固定装置放在目录中(即acts_as_taggable_on/tags.yml)来命名固定装置,这会使显式分配过时。 -> 我将更新我的答案以反映该结果
    • 是的,那就更好了!
    • 谢谢。奇迹般有效。这应该是公认的答案!
    【解决方案2】:

    如果你想使用 TestUnit 然后设置一些标签(在夹具文件 tags.yml 中):

    tag_one:
      name: tag one
    tag_two:
      name: tag two
    

    然后设置标签(在fixture文件taggings.yml中):

    tagging_one:
      tag_id: <%= ActiveRecord::Fixtures.identify(:tag_one) %>
      taggable_id: <%= ActiveRecord::Fixtures.identify(:framework_one) %>
      taggable_type: Framework
      context: tags
    

    基本上,ActiveRecord::Fixtures.identify(:tag_one) 获取标签的 ID 以放入右列。

    【讨论】:

    • 感谢您的想法。在我的情况下(ruby-on-rails4),tags.yml 需要具有显式值的 id。例如,id: &lt;%= ActiveRecord::Fixtures.identify(:tag_one) %&gt;
    • 非常感谢!请注意:从 Rails 4 开始 ActiveRecord::Fixtures 已弃用,只需使用 ActiveRecord::FixtureSet 代替。
    • 这说明了为什么最初接受的答案建议为同一个对象编写多个固定装置很快就会变得难以管理。很高兴看到单个对象如何最终跨越多个固定装置。可以看出,作为单个对象的一部分,忘记哪些固定装置与哪些其他固定装置相关联是多么容易。感谢这个例子。
    【解决方案3】:

    通常最好根据需要即时创建这些类型的东西。夹具很快就会变得非常难以管理,当您将来查看测试时,您将需要查看三到四个夹具文件来了解正在发生的事情。

    我建议您花点时间看看 factory_girl 宝石,它将为您节省大量时间。你会做这样的事情:

    # test/factories.rb
    Factory.define :framework do |f|
      # Add any properties to make a valid Framework instance here, i.e. if you have
      # validates_presence_of :name on the Framework model ...
      f.name 'Test Name'
    end
    

    然后在您的功能或单元测试中,您可以轻松地创建具有单个测试所需的特定属性的对象:

    # Create and save in the DB with default values
    @framework = Factory.create(:framework)
    # Build an object with a different name and don't save it in the DB
    @framework = Factory.build(:framework, :name => 'Other name'
    # Create with tags
    @framework = Factory.build(:framework, :tags_list => 'foo, bar')
    

    【讨论】:

      【解决方案4】:

      使用 :tags_list 对我不起作用:

      > undefined method `tags_list=' for #<Project:0xb610b24>
      

      在你的实际工厂里做了什么,你需要像这样添加它:

      Factory.define(:project) do |f|
        f.tags_list ("factory")
      end
      

      我还发现这需要在父级工厂中,由于某种原因它不适用于子级。我也发现调用

      @framework = Factory.build(:framework, :tag_list => 'foo, bar')
      

      不会抛出错误,但不会悄悄地创建标签。

      希望这会有所帮助!

      【讨论】:

        【解决方案5】:

        这就是我将标签(使用acts-as-taggable-on)添加到我的用户模型(使用factory_girl)的方式:

        FactoryGirl.define do 
          factory :post do 
            ...
            trait :poetry do
              after(:create) { |post| post.update_attributes(tag_list: 'poetry') }
            end
          end
        end
        

        这样,当我只想创建一个普通的Post 对象时,我会写:

        create(:post)
        

        但是当我想创建一个带有poetry 标记的Post 时,我会写:

        create(:post, :poetry)
        

        而且效果很好。

        【讨论】:

          【解决方案6】:

          这是我发现在测试中添加标签的最简单方法。如果您有这样的模型设置:

          class User < ActiveRecord::Base
            acts_as_taggable # Alias for acts_as_taggable_on :tags
            acts_as_taggable_on :skills, :interests
          end
          

          而你正在使用 FactoryGirl,你可以像这样创建它们:

          user1 = create(:user, tag_list: "SomeTag",
                                skill_list: "SomeSkillTag",
                                interest_list: "SomeInterestTag")
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-06-26
            • 2011-10-25
            • 1970-01-01
            • 1970-01-01
            • 2013-12-26
            • 1970-01-01
            • 2016-12-21
            • 1970-01-01
            相关资源
            最近更新 更多