2013-04-30 41 views
22

Điều này có lẽ là ngớ ngẩn đơn giản nhưng tôi không thể tìm thấy một ví dụ ở bất cứ đâu.FactoryGirl ghi đè thuộc tính của đối tượng liên quan

Tôi có hai nhà máy:

FactoryGirl.define do 
    factory :profile do 
    user 

    title "director" 
    bio "I am very good at things" 
    linked_in "http://my.linkedin.profile.com" 
    website "www.mysite.com" 
    city "London" 
    end 
end 

FactoryGirl.define do 
    factory :user do |u| 
    u.first_name {Faker::Name.first_name} 
    u.last_name {Faker::Name.last_name} 

    company 'National Stock Exchange' 
    u.email {Faker::Internet.email} 
    end 
end 

Những gì tôi muốn làm là ghi đè lên một số người sử dụng các thuộc tính khi tôi tạo ra một hồ sơ cá nhân:

p = FactoryGirl.create(:profile, user: {email: "[email protected]"}) 

hoặc một cái gì đó tương tự, nhưng tôi không thể nhận cú pháp đúng. Lỗi:

ActiveRecord::AssociationTypeMismatch: User(#70239688060520) expected, got Hash(#70239631338900) 

Tôi biết tôi có thể làm điều này bằng cách tạo người dùng trước và sau đó liên kết với tiểu sử nhưng tôi nghĩ phải có cách tốt hơn.

Hoặc này sẽ làm việc:

p = FactoryGirl.create(:profile, user: FactoryGirl.create(:user, email: "[email protected]")) 

nhưng điều này dường như quá phức tạp. Có cách nào đơn giản hơn để ghi đè thuộc tính được liên kết không? Cú pháp chính xác cho điều này là gì ??

Trả lời

6

Tôi nghĩ bạn có thể thực hiện công việc này với các cuộc gọi lại và các thuộc tính tạm thời. Nếu bạn thay đổi nhà máy cá nhân của bạn như sau:

FactoryGirl.define do 
    factory :profile do 
    user 

    ignore do 
     user_email nil # by default, we'll use the value from the user factory 
    end 

    title "director" 
    bio "I am very good at things" 
    linked_in "http://my.linkedin.profile.com" 
    website "www.mysite.com" 
    city "London" 

    after(:create) do |profile, evaluator| 
     # update the user email if we specified a value in the invocation 
     profile.user.email = evaluator.user_email unless evaluator.user_email.nil? 
    end 
    end 
end 

sau đó bạn sẽ có thể gọi nó như thế này và nhận được kết quả mong muốn:

p = FactoryGirl.create(:profile, user_email: "[email protected]") 

tôi đã không kiểm tra nó, mặc dù.

+0

Cảm ơn, nhưng tôi muốn điều đó làm việc cho bất kỳ thuộc tính nào, vì vậy tôi sẽ không muốn mã hóa nó cho mỗi loại như vậy. Có lẽ không ai khác cần điều này ... – bobomoreno

+2

Tôi nghĩ rằng ví dụ của bạn có lỗi. Thay đổi 'after (: create)' thành 'profile.user.email = evaluator.user_email trừ khi evaluator.user_email.nil?' – Kelly

18

Theo một trong những người sáng tạo của FactoryGirl, bạn không thể chuyển đối số động cho trình trợ giúp của liên kết (Pass parameter in setting attribute on association in FactoryGirl).

Tuy nhiên, bạn sẽ có thể làm điều gì đó như thế này:

FactoryGirl.define do 
    factory :profile do 
    transient do 
     user_args nil 
    end 
    user { build(:user, user_args) } 

    after(:create) do |profile| 
     profile.user.save! 
    end 
    end 
end 

Sau đó, bạn có thể gọi nó gần giống như bạn muốn:

p = FactoryGirl.create(:profile, user_args: {email: "[email protected]"}) 
+2

Câu trả lời hay. Bạn có cập nhật điều này để tuân thủ các phiên bản Rails mới nhất hay không. Ví dụ. Tôi nhận được thông báo "DEPRECATION WARNING:' # ignore' không được chấp nhận và sẽ bị xóa trong phiên bản 5.0 ". khi thực hiện câu trả lời này. –

+0

Tôi đã gặp sự cố này trong Rails 5 –

+0

Bạn có thể sử dụng "thoáng qua" thay vì "bỏ qua" để loại bỏ cảnh báo –

3

Giải quyết nó bằng cách tạo tài khoản đầu tiên, và sau đó hồ sơ :

my_user = FactoryGirl.create(:user, user_email: "[email protected]") 
my_profile = FactoryGirl.create(:profile, user: my_user.id) 

Vì vậy, điều này gần giống như trong câu hỏi, được chia thành hai dòng. Chỉ có sự khác biệt thực sự là quyền truy cập rõ ràng vào ".id". Đã được thử nghiệm với Rails 5.

Các vấn đề liên quan