22

tôi đang nhân bản một hiệp hội single-level như thế này:ActiveRecord: Làm thế nào tôi có thể sao chép các liên kết lồng nhau?

class Survey < ActiveRecord::Base 
    def duplicate 
    new_template = self.clone 
    new_template.questions << self.questions.collect { |question| question.clone } 
    new_template.save 
    end 
end 

Vì vậy mà nhái các Survey sau đó bắt chước các Questions liên quan đến khảo sát đó. Khỏe. Điều đó hoạt động khá tốt.

Nhưng điều tôi đang gặp phải là mỗi câu hỏi has_manyAnswers. Vì vậy, Survey has_many Questions which has_many Answers.

Tôi không thể tìm ra cách sao chép các câu trả lời đúng cách. Tôi đã thử điều này:

def duplicate 
    new_template = self.clone 

    self.questions.each do |question| 
    new_question = question.clone 
    new_question.save 

    question.answers.each do |answer| 
     new_answer = answer.clone 
     new_answer.save 
     new_question.answers << answer 
    end 

    new_template.questions << question 
    end 

    new_template.save 
end 

Nhưng một số công cụ kỳ lạ thực sự thay thế câu trả lời gốc rồi tạo câu trả lời mới, vì vậy, ID của bạn khớp chính xác.

Trả lời

45

Sử dụng deep_clonable gem

new_survey = original_survey.clone :include => [:questions => :answers] 
+17

Gosh của tôi. Anh yêu em. – Shpigford

+2

phương thức sao chép đã đổi thành chế độ dup. xem [repo readme] (https://github.com/moiristo/deep_cloneable) –

+6

Và bây giờ nó thay đổi thành: new_survey = original_survey.deep_clone: ​​include => [: questions =>: answers] – halbano

3

Bạn cũng có thể giống như Amoeba gem cho ActiveRecord 3.2.

Trong trường hợp của bạn, bạn có thể muốn sử dụng các tùy chọn nullify, regex hoặc prefix có sẵn trong DSL cấu hình.

Hỗ trợ sao chép đệ quy dễ dàng và tự động của các liên kết has_one, has_manyhas_and_belongs_to_many, xử lý trước trường và DSL cấu hình linh hoạt và mạnh mẽ có thể áp dụng cho cả mô hình và khi đang di chuyển.

hãy chắc chắn kiểm tra Amoeba Documentation nhưng sử dụng khá dễ dàng ...

chỉ

gem install amoeba 

hoặc thêm

gem 'amoeba' 

để Gemfile bạn

sau đó thêm khối amip theo mô hình của bạn và chạy phương thức dup như thường lệ

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    enable 
    end 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

class Tag < ActiveRecord::Base 
    has_and_belongs_to_many :posts 
end 

class PostsController < ActionController 
    def some_method 
    my_post = Post.find(params[:id]) 
    new_post = my_post.dup 
    new_post.save 
    end 
end 

Bạn cũng có thể kiểm soát các lĩnh vực được sao chép trong rất nhiều cách, nhưng ví dụ, nếu bạn muốn ngăn chặn ý kiến ​​khỏi bị giống nhau nhưng bạn muốn duy trì các thẻ tương tự, bạn có thể làm một cái gì đó như thế này:

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    exclude_field :comments 
    end 
end 

Bạn cũng có thể tiền xử lý các trường để giúp cho biết tính duy nhất với cả tiền tố và hậu tố cũng như regex. Bên cạnh đó, cũng có nhiều tùy chọn để bạn có thể viết theo kiểu dễ đọc nhất cho mục đích của bạn:

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    include_field :tags 
    prepend :title => "Copy of " 
    append :contents => " (copied version)" 
    regex :contents => {:replace => /dog/, :with => "cat"} 
    end 
end 

sao chép đệ quy của các hiệp hội rất dễ dàng, chỉ cần kích hoạt amip trên các mô hình con cũng

class Post < ActiveRecord::Base 
    has_many :comments 

    amoeba do 
    enable 
    end 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
    has_many :ratings 

    amoeba do 
    enable 
    end 
end 

class Rating < ActiveRecord::Base 
    belongs_to :comment 
end 

DSL cấu hình có nhiều tùy chọn hơn, vì vậy hãy chắc chắn kiểm tra tài liệu.

Tận hưởng! :)

+1

Tôi thực sự đã thử đá quý này. Nó rất hứa hẹn, nhưng chưa sẵn sàng. Tôi đã có hai vấn đề với nó, cả hai mà tôi đăng trở lại dự án github, nhưng cuối cùng đã bỏ và viết chức năng sao chép của tôi bằng tay, sử dụng dup. Tôi hy vọng sẽ thử lại sau vài tháng và có may mắn hơn! – Rob

-1

Bạn cũng có thể bí danh ray phương pháp dup, như sau:

class Survey 
    has_many :questions, :inverse_of=>:survey, :autosave=>true 
    alias orig_dup dup 
    def dup 
     copy=orig_dup 
     copy.questions=questions 
     copy 
    end 
end 

class Questions 
    belongs_to :survey, :inverse_of=>:questions 
    has_many :answers, :inverse_of=>:question, :autosave=>true 
    alias orig_dup dup 
    def dup 
     copy=orig_dup 
     copy.answers=answers 
     copy 
    end 
end 

class Answer 
    belongs_to :question 
end 

và sau đó bạn có thể làm điều này

aaa = Survey.find(123).dup 
aaa.save 
0

nên không đó là ..

new_question.answers << new_answer 
end 

new_template.questions << new_question 
Các vấn đề liên quan