2016-05-07 43 views
2

我想爲has_many/has_many關係定義一個工廠(我認爲它是正確的)但我不知道如何定義這些創建的工廠的每個對象的屬性。Rails 4/Factory Girl - has_many/has_many factory並定義了不同的對象

這裏是主頁,它是交易

的卡的列表,我們認爲下面的主頁視圖是一個已登錄的用戶(注CURRENT_USER來自設計)。

<% @deals.each do |deal| %> 
    @userdeal = UserDeal.where('user_id = ? AND deal_id = ?', current_user.id, deal.id).take 

    <div> 
     <div class="button"> 
     <% if @userdeal.number_of_clicks = 4 %>you reached the maximum clicks 
     <% end %> 
     </div> 
    </div> 
    <% end %> 

基本上如果用戶有特定交易(在桌子上user_deals,看到模型下面)一user_deal.number_of_clicks = 4那麼,該卡的按鈕將這樣的消息出現在「你到達最大點擊次數「。如果點擊次數爲< 4,則不顯示任何按鈕。

所以我想在功能測試中使用工廠,我將檢查如果我用fatcory女孩創建一個對象@ userdeal1,其中用戶達到4次點擊,在此卡片上他看到按鈕及其文本,但對於其他交易他什麼都看不到。

這裏是我到目前爲止

車型

class Deal < ActiveRecord::Base 
    has_many :user_deals,   dependent: :destroy 
    has_many :users,    through: :user_deals 
end 

class User < ActiveRecord::Base 
    has_many :user_deals   
    has_many :deals,    through: :user_deals 
end 

class UserDeal < ActiveRecord::Base 
    belongs_to :user,   :foreign_key => 'user_id' 
    belongs_to :deal,   :foreign_key => 'deal_id' 
end 

而且表user_deal

# Table name: user_deals 
# 
# id     :integer   not null, primary key 
# user_id   :integer 
# deal_id   :integer 
# number_of_clicks :integer   default(0) 
# created_at   :datetime 
# updated_at   :datetime 

到目前爲止,我發現的結構如何創建

FactoryGirl.define do 
    factory :user_deal do 
    association :user 
    association :deal 

end 

事實上rygirl自述我創造了這個:

FactoryGirl.define do 
    factory :user do 

    sequence(:email) { |n| "person#{n}@example.com"} 
    password "vddfdf" 
    password_confirmation "vddfdf" 
     confirmed_at Time.now 
     confirmation_token nil 

    factory :superadmin do 
     after(:create) {|user| user.add_role(:superadmin)} 
    end 

    after(:create) do |user| 
     user.deals << FactoryGirl.create(:deal) 
    end 

    factory :user_with_deals do 
     # used for defining user_deals 
     transient do 
     deals_count 5 
     end 
     after(:create) do |user, evaluator| 
     create_list(:deal, evaluator.deals_count, user: user) 
     end 
    end 

    end 
end 

但現在我不知道怎麼說「OK在這些工廠創建user_deals之一,我想一個有NUMBER_OF_CLICKS = 4,另外一個NUMBER_OF_CLICKS = 1)。所以我試圖直接把這個測試中,如下圖所示:

describe 'HP deal card features', :type => :feature do 

    context "As signed-in USER" do 
    let(:subject) { ApplicationController.new } 

    before do  
     @user = FactoryGirl.create(:user, :user_country_name => 'Germany') 
     @deal1 = FactoryGirl.build(:deal) 
     @deal2 = FactoryGirl.build(:deal) 
     @user_deal_with_max_of_clicks = FactoryGirl.build(:user_with_deals, 
                  :user    => @user, 
                  :deal    => @deal1, 
:number_of_clicks => 4 
                 ).save(validate: false) 
     @user_deal_with_clicks_available = FactoryGirl.build(:user_with_deals, 
                  :user    => @user, 
                  :deal    => @deal2, 
number_of_clicks => 1 # still has clicks 
                 ).save(validate: false) 
    it "the right behavior for the buttons telling him how many clicks he has left" do 

     sign_in @user 
     visit root_path 
     # I'll find a way to test here if there is the text "you reached the maximum clicks" for the first card and not for the second 
    end 
    after do 
     visit destroy_user_session_path 
    end 

    end 

但測試不工作,並給我根據小的變化我嘗試不同類型的錯誤。我很確定我沒有設法真正創建2個對象user_deals,其中一個的number_of_clicks = 4,另一個的number_of_clicks = 1。

編輯

後請求發佈錯誤:如果我的@user_deal_with_max_of_clicks內離開

「:用戶=> @user和:對付=> @ deal1」,我得到

NoMethodError: 
     undefined method `user=' for #<User:0x0000000b4754e0> 

NoMethodError: 
     undefined method `deal=' for #<User:0x0000000b451568> 

但我刪除列如下:

@user_deal_with_max_of_clicks = FactoryGirl.build(:user_with_deals,                
    :number_of_clicks => 4 
                 ).save(validate: false) 

然後我得到這個錯誤:

NoMethodError: 
     undefined method `number_of_clicks=' for #<User:0x0000000b46ce80> 

EDIT 2

utilities.rb

include ApplicationHelper 

def sign_in(user) 
    visit new_user_session_path 
    fill_in  I18n.t("formtastic.labels.user.email"),   with: user.email 
    fill_in  I18n.t("formtastic.labels.user.password"),  with: user.password 
    click_on I18n.t("devise.sessions.login_page.login") 
end 
+0

燦你發佈了它給你的錯誤? – mysmallidea

+0

@mysmallidea請參閱編輯 – Mathieu

回答

2

首先,我'd建議你使用let。有一個偉大的指南,寫cleaner and better specs。其次,建立良好的工廠至關重要。它們將極大地簡化測試過程:

所以出發,您的用戶工廠可以加以調整,

FactoryGirl.define do 
    factory :user do 
    sequence(:email) { |n| "person#{n}@example.com" } 

    password "vddfdf" 
    password_confirmation "vddfdf" 

    confirmed_at Time.now 
    confirmation_token nil 

    trait :superadmin do 
     role :superadmin 
    end 

    trait :with_deals do 
     after(:create) do |user| 
     create_list(:deal, 5, user: user) 
     end 
    end 
    end 
end 

Traits是很好的方式,選擇性地調整工廠。所以,如果你希望你的用戶是超級管理員,現在只需使用

create(:user, :superadmin) 

想和交易的超級管理員?簡單。

create(:user, :superadmin, :with_deals) 

您還沒有發佈您的交易工廠,但我敢肯定,你可以將這些技巧適應他們。

最後,導致user_deals。在您當前的工廠中,您沒有找到您的number_of_clicks專欄。

同樣,你可以很容易地設置這與性狀:

FactoryGirl.define do 
    factory :user_deal do 
    association :user 
    association :deal 

    trait :few_clicks do 
     number_of_clicks 1 
    end 

    trait :many_clicks do 
     number_of_clicks 4 
    end 
    end 
end 

我們的規範本身,所學習的技巧這是一個容易的任務來設置您需要的關係:

describe 'HP deal card features', :type => :feature do 
    context "As signed-in USER" do 
    let(:subject) { ApplicationController.new } 
    let(:user) { create(:user, user_country_name: 'Germany') } 
    let(:deal1) { create(:deal) } 
    let(:deal2) { create(:deal) } 

    before do 
     create(:user_deal, :few_clicks, user: user, deal: deal1) 
     create(:user_deal, :many_clicks, user: user, deal: deal2) 
    end 

    it "tells the user how many clicks he has left" do 
     sign_in user 
     visit root_path 
     # I'll find a way to test here if there is the text "you reached the maximum clicks" for the first card and not for the second 
    end 

    after do 
     visit destroy_user_session_path 
    end 
    end 
end 
+0

感謝您的建議。顯然我需要清理一些事情。會做。我會現在測試你的應用程序的建議。 – Mathieu

+0

我得到一個錯誤,報告錯誤的行甚至不在「它告訴用戶他剩下多少次點擊」的內部,而是在「之前做」的內部:它在行「create(:user_deal, (#),這個錯誤是:ActiveRecord :: AssociationTypeMismatch: Deal(#86165360)預計,得到TrueClass(#14299980) – Mathieu

+0

順便說一下,我可以使用save(validate:false) )創建事物的方式(let(:deal1){create(:deal)}?實際上我需要跳過嚴格的驗證。這就是爲什麼我使用FactoryGirl.build().save(validate:false)我真正的應用程序,我添加了其他屬性,如日期,我不需要在測試中驗證) – Mathieu

相關問題