Si vous avez des colonnes de base de données created_at
et updated_at
Rails définit automatiquement ces valeurs lorsque vous créez et mettez à jour un objet de modèle. Existe-t-il un moyen d'enregistrer le modèle sans toucher ces colonnes?
J'apporte des données héritées et je voudrais définir ces valeurs à partir des valeurs correspondantes dans les champs de données hérités (différemment nommés). Je trouve quand je les place sur le modèle et que j'enregistre le modèle, Rails semble remplacer les valeurs entrantes.
Bien sûr, je pourrais simplement nommer les colonnes du modèle Rails différemment pour éviter cela, mais après l'importation des données, je veux que Rails fasse son horodatage automatique).
Faites-le dans une migration ou dans une tâche de râteau (ou dans les nouvelles graines de base de données si vous êtes sur Edge Rails):
ActiveRecord::Base.record_timestamps = false
begin
run_the_code_that_imports_the_data
ensure
ActiveRecord::Base.record_timestamps = true # don't forget to enable it again!
end
Vous pouvez définir en toute sécurité created_at
et updated_at
manuellement, Rails ne se plaindra pas.
Remarque: Cela fonctionne également sur des modèles individuels, par ex. User.record_timestamps = false
utilisez plutôt la méthode update_column:
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
update_column(name, value)
# Updates a single attribute of an object, without calling save.
La validation est ignorée.
Les rappels sont ignorés.
la colonne updated_at/updated_on n'est pas mise à jour si cette colonne est disponible.
Déclenche une ActiveRecordError lorsqu'elle est appelée sur de nouveaux objets ou lorsque l'attribut name est marqué en lecture seule.
Rails 5 fournit un moyen pratique de mettre à jour un enregistrement sans mettre à jour son horodatage updated_at
: https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save
Vous avez juste besoin de passer touch:false
lors de la mise à jour de votre dossier.
>> user = User.first
>> user.updated_at
=> Thu, 28 Apr 2016 20:01:57 IST +05:30
>> user.name = "Jose"
>> user.save(touch: false)
=> true
>> user.updated_at
=> Thu, 28 Apr 2016 20:01:57 IST +05:30
Vous pouvez définir les éléments suivants dans votre migration:
ActiveRecord::Base.record_timestamps = false
Ou utilisez également update_all:
pdate_all (mises à jour, conditions = néant, options = {})
Met à jour tous les enregistrements avec les détails fournis s'ils correspondent à un ensemble de conditions fournies, des limites et une commande peuvent également être fournies. Cette méthode construit une seule instruction SQL UPDATE et l'envoie directement à la base de données. Il n'instancie pas les modèles impliqués et ne déclenche pas de rappels Active Record.
Dans Rails 3+, pour un seul objet, définissez record_timestamps
pour l'objet plutôt que pour la classe. C'est à dire.,
>> user = User.first
>> user.updated_at
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00
>> user.name = "Jose"
=> "Jose"
>> user.record_timestamps = false
>> user.save
=> true
>> user.updated_at
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00
>> User.record_timestamps
=> true
De cette façon, vous ne touchez pas à l'état global du modèle et vous n'avez pas à vous rappeler de restaurer le paramètre précédent dans un bloc ensure
.
Comme il s'agit d'une importation unique, vous pouvez effectuer les opérations suivantes:
legacy_created_at
et legacy_updated_at
des champs.#save
et ne vous inquiétez généralement pas de l'utilisation de update_all
ou similaire, et vous pouvez utiliser des rappels si vous le souhaitez.created_at
et updated_at
.J'aime utiliser un module mixin pour désactiver temporairement l'horodatage dans un bloc:
module WithoutTimestamps
def without_timestamps
old = ActiveRecord::Base.record_timestamps
ActiveRecord::Base.record_timestamps = false
begin
yield
ensure
ActiveRecord::Base.record_timestamps = old
end
end
end
Ensuite, vous pouvez l'utiliser où vous en avez besoin
class MyModel < ActiveRecord::Base
include WithoutTimestamps
def save_without_timestamps
without_timestamps do
save!
end
end
end
Ou tout simplement comme ceci:
m = MyModel.find(1)
WithoutTimestamps.without_timestamps do
m.save!
end
Lorsque vous n'êtes pas dans une importation en bloc, vous pouvez remplacer les should_record_timestamps? sur votre modèle pour ajouter de nouvelles vérifications sur le moment de la mise à jour de la colonne updated_at.
En me référant à d'autres réponses, j'ai trouvé à ma grande surprise que la désactivation des horodatages pour un seul modèle, comme dans:
User.record_timestamps = false
travaillé pour ma base de données de développement, mais pas sur ma base de données de pré-production, qui fonctionne sur un serveur différent. Cependant, cela fonctionne si je désactive les horodatages pour tous les modèles avec
ActiveRecord::Base.record_timestamps = false
(Situation: modification de l'attribut created_at dans une migration)
Je n'ai pas pu faire ActiveRecord::Base.record_timestamps
flag change quoi que ce soit, et la seule façon de travailler est d'utiliser ActiveRecord::Base.no_touching {}
:
ActiveRecord::Base.no_touching do
Project.first.touch # does nothing
Message.first.touch # does nothing
end
Project.no_touching do
Project.first.touch # does nothing
Message.first.touch # works, but does not touch the associated project
end
Tiré de ici .
Ceci est très utile pour les tâches de rake où vous devez remplacer certaines propriétés de modèles profondément liés et ne pas vous soucier des rappels internes, tandis que vos utilisateurs comptent sur created_at
ou updated_at
les attributs ou ceux-ci sont utilisés comme colonnes de tri.
Ou, pour la sécurité des threads, voir: http://www.hungryfools.com/2007/07/turning-off-activerecord-timestamp.html