2011-08-22 25 views
50

Tôi có một Mô hình người dùng thuộc về một Nhóm. Nhóm phải có thuộc tính tên duy nhất. Nhà máy của người dùng và nhà máy nhóm được định nghĩa là:Tìm hoặc tạo bản ghi thông qua liên kết factory_girl

Factory.define :user do |f| 
    f.association :group, :factory => :group 
    # ... 
end 

Factory.define :group do |f| 
    f.name "default" 
end 

Khi người dùng đầu tiên được tạo nhóm mới cũng được tạo. Khi tôi cố gắng tạo một người dùng thứ hai nó không thành công vì nó muốn tạo lại một nhóm.

Có cách nào để nói phương pháp kết hợp factory_girl để tìm kiếm đầu tiên cho một bản ghi hiện có không?

Lưu ý: Tôi đã cố gắng xác định một phương pháp để xử lý điều này, nhưng sau đó tôi không thể sử dụng f.association. Tôi muốn có thể sử dụng nó trong các trường hợp của Cucumber như sau:

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 

và điều này chỉ có thể hoạt động nếu liên kết được sử dụng trong Định nghĩa nhà máy.

Trả lời

16

tôi đã kết thúc bằng cách kết hợp các phương pháp tìm thấy khắp nơi trên mạng, một trong số họ được thừa hưởng như đề xuất bởi duckyfuzz trong một câu trả lời khác.

tôi đã sau:

# in groups.rb factory 

def get_group_named(name) 
    # get existing group or create new one 
    Group.where(:name => name).first || Factory(:group, :name => name) 
end 

Factory.define :group do |f| 
    f.name "default" 
end 

# in users.rb factory 

Factory.define :user_in_whatever do |f| 
    f.group { |user| get_group_named("whatever") } 
end 
1

Thông thường tôi chỉ thực hiện nhiều định nghĩa nhà máy. Một cho một người sử dụng với một nhóm và một cho một người sử dụng groupless:

Factory.define :user do |u| 
    u.email "email" 
    # other attributes 
end 

Factory.define :grouped_user, :parent => :user do |u| 
    u.association :group 
    # this will inherit the attributes of :user 
end 

Sau đó, bạn có thể sử dụng các định nghĩa trong bước của bạn để tạo người dùng và nhóm seperatly và tham gia cùng họ lại với nhau theo ý thích. Ví dụ: bạn có thể tạo một người dùng được nhóm và một người dùng đơn lẻ và tham gia người dùng duy nhất vào nhóm người dùng được nhóm.

Dù sao, bạn nên có một cái nhìn tại pickle gem mà sẽ cho phép bạn viết các bước như:

nhà máy
Given a user exists with email: "[email protected]" 
And a group exists with name: "default" 
And the user: "[email protected]" has joined that group 
When somethings happens.... 
0

Tôi đang sử dụng một cách chính xác kịch bản dưa chuột bạn mô tả trong câu hỏi của bạn:

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 

Bạn có thể mở rộng nó thích:

Given the following user exists: 
    | Email   | Group   | 
    | [email protected] | Name: mygroup | 
    | [email protected] | Name: mygroup | 
    | [email protected] | Name: mygroup | 

này sẽ tạo 3 người dùng với nhóm "mygroup". Vì nó được sử dụng như thế này sử dụng chức năng 'find_or_create_by', cuộc gọi đầu tiên tạo nhóm, hai cuộc gọi tiếp theo tìm thấy nhóm đã được tạo.

89

Bạn có thể sử dụng initialize_with với find_or_create phương pháp

FactoryGirl.define do 
    factory :group do 
    name "name" 
    initialize_with { Group.find_or_create_by_name(name)} 
    end 

    factory :user do 
    association :group 
    end 
end 

Nó cũng có thể được sử dụng với id

FactoryGirl.define do 
    factory :group do 
    id  1 
    attr_1 "default" 
    attr_2 "default" 
    ... 
    attr_n "default" 
    initialize_with { Group.find_or_create_by_id(id)} 
    end 

    factory :user do 
    association :group 
    end 
end 

Đối với Rails 4

Cách đúng trong Rails 4 là Group.find_or_create_by(name: name) , vì vậy, bạn nên sử dụng

Thay vào đó, 210
initialize_with { Group.find_or_create_by(name: name) } 

.

+6

Hoạt động rất tốt, cảm ơn. Trong Rails 4, cách ưa thích sẽ là: 'Group.find_or_create_by (name: name)' – migu

+19

Cách ưa thích trong Rails 4 thực sự là 'Group.where (name: name) .first_or_create'. – Laurens

+0

Điều này có lẽ là câu trả lời được chấp nhận. Drive-by-ers ... đây là giải pháp của bạn. – ocodo

4

Bạn cũng có thể sử dụng một chiến lược FactoryGirl để đạt được điều này

module FactoryGirl 
    module Strategy 
    class Find 
     def association(runner) 
     runner.run 
     end 

     def result(evaluation) 
     build_class(evaluation).where(get_overrides(evaluation)).first 
     end 

     private 

     def build_class(evaluation) 
     evaluation.instance_variable_get(:@attribute_assigner).instance_variable_get(:@build_class) 
     end 

     def get_overrides(evaluation = nil) 
     return @overrides unless @overrides.nil? 
     evaluation.instance_variable_get(:@attribute_assigner).instance_variable_get(:@evaluator).instance_variable_get(:@overrides).clone 
     end 
    end 

    class FindOrCreate 
     def initialize 
     @strategy = FactoryGirl.strategy_by_name(:find).new 
     end 

     delegate :association, to: :@strategy 

     def result(evaluation) 
     found_object = @strategy.result(evaluation) 

     if found_object.nil? 
      @strategy = FactoryGirl.strategy_by_name(:create).new 
      @strategy.result(evaluation) 
     else 
      found_object 
     end 
     end 
    end 
    end 

    register_strategy(:find, Strategy::Find) 
    register_strategy(:find_or_create, Strategy::FindOrCreate) 
end 

Bạn có thể sử dụng this gist. Và sau đó làm như sau

FactoryGirl.define do 
    factory :group do 
    name "name" 
    end 

    factory :user do 
    association :group, factory: :group, strategy: :find_or_create, name: "name" 
    end 
end 

Điều này làm việc cho tôi, mặc dù.

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