Jak najłatwiej powielić rekord activerecord?
Chcę zrobić kopię rekordu activerecord, zmieniając Pojedyncze pole w procesie (oprócz id ). Jaki jest najprostszy sposób, aby to osiągnąć?
Zdaję sobie sprawę, że mogę utworzyć nowy rekord, a następnie iterację nad każdym z pól kopiując dane pole po polu-ale pomyślałem, że musi być łatwiejszy sposób, aby to zrobić...
Takie jak:
@newrecord=Record.copy(:id) *perhaps?*
11 answers
Aby uzyskać kopię, użyj metody clone (lub dup dla rails 3.1+):
# rails < 3.1
new_record = old_record.clone
#rails >= 3.1
new_record = old_record.dup
Następnie możesz zmienić dowolne pola.
ActiveRecord nadpisuje wbudowany obiekt # clone , aby dać Ci nowy (nie zapisany do DB) rekord z niepodpisanym identyfikatorem.
Zauważ, że nie kopiuje skojarzeń, więc w razie potrzeby musisz to zrobić ręcznie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-29 19:38:56
W zależności od twoich potrzeb i stylu programowania, możesz również użyć kombinacji nowej metody klasy i merge. Z powodu braku lepszego prostego przykładu Załóżmy, że masz zadanie zaplanowane na określoną datę i chcesz je powielić na inną datę. Rzeczywiste atrybuty zadania nie są ważne, więc:
old_task = Task.find(task_id) new_task = Task.new(old_task.attributes.merge({:scheduled_on => some_new_date}))
Utworzy nowe zadanie z :id => nil
, :scheduled_on => some_new_date
, i wszystkie inne atrybuty takie same jak oryginalne zadanie. Korzystanie Z Zadania.Nowy, trzeba będzie wyraźnie zadzwonić Zapisz, więc jeśli chcesz go zapisać automatycznie, Zmień zadanie.nowy w zadaniu.twórz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 13:48:34
Możesz również polubić amoeba gem dla ActiveRecord 3.2.
W Twoim przypadku, prawdopodobnie chcesz skorzystać z nullify
, regex
lub prefix
opcje dostępne w konfiguracji DSL.
Obsługuje łatwe i automatyczne powtarzanie rekurencyjne has_one
, has_many
i has_and_belongs_to_many
Asocjacje, wstępne przetwarzanie pola oraz wysoce elastyczna i wydajna konfiguracja DSL, która może być stosowana zarówno do modelu, jak i w locie.
Koniecznie sprawdź Amoeba Dokumentacja ale korzystanie z niej jest całkiem proste...
Po prostu
gem install amoeba
Lub dodać
gem 'amoeba'
Do Twojego Gemfile
Następnie Dodaj blok ameba do modelu i uruchom metodę dup
jak zwykle
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
Możesz również kontrolować, które pola są kopiowane na wiele sposobów, ale na przykład, jeśli chcesz zapobiec powielaniu komentarzy, ale chcesz zachować te same tagi, możesz zrobić coś takiego:
class Post < ActiveRecord::Base
has_many :comments
has_and_belongs_to_many :tags
amoeba do
exclude_field :comments
end
end
Możesz również wstępnie przetworzyć pola pomagające wskazywać unikalność zarówno za pomocą prefiksów i przyrostków, jak i wyrażeń regularnych. Ponadto, istnieje również wiele opcji, dzięki czemu można pisać w najbardziej czytelnym stylu dla swojego celu:
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
Rekurencyjne kopiowanie skojarzeń jest łatwe, wystarczy włączyć ameba również na modelach potomnych
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
Konfiguracja DSL ma jeszcze więcej opcji, więc koniecznie zapoznaj się z dokumentacją.
Smacznego! :)Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-28 16:27:38
Użyj ActiveRecord:: Base#dup jeśli nie chcesz kopiować id
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-18 16:58:40
Zwykle kopiuję atrybuty, zmieniając to, co trzeba zmienić:
new_user = User.new(old_user.attributes.merge(:login => "newlogin"))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-29 20:35:58
Jeśli potrzebujesz głębokiej kopii ze skojarzeniami, polecam gem deep_cloneable.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-01 02:22:49
W Rails 5 możesz po prostu utworzyć duplikat obiektu lub rekord w ten sposób.
new_user = old_user.dup
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-04 08:56:28
Oto przykład nadpisującej metody ActiveRecord #dup
do dostosowywania duplikacji instancji i dołączania duplikacji relacji:
class Offer < ApplicationRecord
has_many :offer_items
def dup
super.tap do |new_offer|
# change title of the new instance
new_offer.title = "Copy of #{@offer.title}"
# duplicate offer_items as well
self.offer_items.each { |offer_item| new_offer.offer_items << offer_item.dup }
end
end
end
Uwaga: ta metoda nie wymaga żadnego zewnętrznego kleju, ale wymaga nowszej wersji ActiveRecord z zaimplementowaną metodą #dup
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 07:04:13
Prosty sposób to:
#your rails >= 3.1 (i was done it with Rails 5.0.0.1)
o = Model.find(id)
# (Range).each do |item|
(1..109).each do |item|
new_record = o.dup
new_record.save
end
Lub
# if your rails < 3.1
o = Model.find(id)
(1..109).each do |item|
new_record = o.clone
new_record.save
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-30 13:58:00
Możesz również sprawdzićacts_as_inheritable gem.
"Acts As Inheritable to klejnot Ruby napisany specjalnie dla modeli Rails/ActiveRecord. Jest on przeznaczony do użycia z asocjacją Self-Referential, lub z modelem posiadającym rodzica, który posiada dziedziczone atrybuty. Pozwoli to na dziedziczenie dowolnego atrybutu lub relacji z modelu nadrzędnego."
Dodając acts_as_inheritable
do swoich Modeli będziesz miał dostęp do tych metody:
Inherit_attributes
class Person < ActiveRecord::Base
acts_as_inheritable attributes: %w(favorite_color last_name soccer_team)
# Associations
belongs_to :parent, class_name: 'Person'
has_many :children, class_name: 'Person', foreign_key: :parent_id
end
parent = Person.create(last_name: 'Arango', soccer_team: 'Verdolaga', favorite_color:'Green')
son = Person.create(parent: parent)
son.inherit_attributes
son.last_name # => Arango
son.soccer_team # => Verdolaga
son.favorite_color # => Green
Inherit_relations
class Person < ActiveRecord::Base
acts_as_inheritable associations: %w(pet)
# Associations
has_one :pet
end
parent = Person.create(last_name: 'Arango')
parent_pet = Pet.create(person: parent, name: 'Mango', breed:'Golden Retriver')
parent_pet.inspect #=> #<Pet id: 1, person_id: 1, name: "Mango", breed: "Golden Retriver">
son = Person.create(parent: parent)
son.inherit_relations
son.pet.inspect # => #<Pet id: 2, person_id: 2, name: "Mango", breed: "Golden Retriver">
Mam nadzieję, że to ci pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-27 22:27:24
Ponieważ może być więcej logiki, podczas powielania modelu, sugerowałbym utworzenie nowej klasy, w której będziesz obsługiwał całą potrzebną logikę. Aby to ułatwić, istnieje klejnot, który może pomóc: clowne
Zgodnie z przykładami dokumentacji, dla modelu Użytkownika:
class User < ActiveRecord::Base
# create_table :users do |t|
# t.string :login
# t.string :email
# t.timestamps null: false
# end
has_one :profile
has_many :posts
end
Tworzysz klasę klonera:
class UserCloner < Clowne::Cloner
adapter :active_record
include_association :profile, clone_with: SpecialProfileCloner
include_association :posts
nullify :login
# params here is an arbitrary Hash passed into cloner
finalize do |_source, record, params|
record.email = params[:email]
end
end
class SpecialProfileCloner < Clowne::Cloner
adapter :active_record
nullify :name
end
A następnie użyj go:
user = User.last
#=> <#User(login: 'clown', email: '[email protected]')>
cloned = UserCloner.call(user, email: '[email protected]')
cloned.persisted?
# => false
cloned.save!
cloned.login
# => nil
cloned.email
# => "[email protected]"
# associations:
cloned.posts.count == user.posts.count
# => true
cloned.profile.name
# => nil
Przykład skopiowany z projektu, ale da jasną wizję tego, co można osiągnąć.
Na szybki i prosty zapis wybrałbym:
Model.new(Model.last.attributes.reject {|k,_v| k.to_s == 'id'}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 14:28:51