2009-05-14 6 views
54

Si vous avez des colonnes DB created_at et updated_at Rails définira automatiquement ces valeurs lorsque vous créez et mettez à jour un objet de modèle. Y a-t-il un moyen de sauvegarder 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 ai placés sur le modèle, puis sauvegardez le modèle, Rails semble remplacer les valeurs entrantes.Existe-t-il un moyen d'éviter la mise à jour automatique des champs d'horodatage Rails?

Bien sûr, je pourrais simplement nommer les colonnes du modèle Rails différemment pour éviter cela, mais une fois les données importées, je veux que Rails fasse son horodatage automatique.

Répondre

66

Pour ce faire, dans une migration ou une tâche de râteau (ou the new database seeds si vous êtes sur des rails de bord):

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 en toute sécurité mis 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

+3

Vous pouvez même extraire ceci dans une méthode, par ex. 'without_timestamps def vieux = ActiveRecord :: Base.record_timestamps ActiveRecord :: Base.record_timestamps = false commencer rendement assurer ActiveRecord :: Base.record_timestamps = old end end' – nonrectangular

+1

Avons-nous besoin de le réinitialiser à 'true' même lors de l'exécution de scripts ou de code dans la console? – oldergod

+2

Je pense que http://stackoverflow.com/a/37193298/1214748 est beaucoup mieux. Il ne l'éteint pas globalement pour toute l'application – maschwenk

28

Vous pouvez définir les paramètres suivants dans votre migration:

ActiveRecord::Base.record_timestamps = false 

Ou utilisez Altenatively update_all:

update_all (mises à jour, conditions = nul, options = {})

Met à jour tous les enregistrements avec les détails donnés s'ils correspondent à un ensemble de conditions fourni, les limites et la commande ca n également être fourni. Cette méthode construit une instruction SQL UPDATE unique et envoie directement à la base de données. Il n'instancie pas les modèles impliqués et ne déclenche pas les rappels actifs .

3

Puisque c'est une importation unique, vous pouvez effectuer les opérations suivantes:

  1. modèle créé à l'aide legacy_created_at et legacy_updated_at champs.
  2. Charger les données héritées. Mappez dans les champs du modèle comme vous le souhaitez. Vous pouvez utiliser #save et ne vous souciez généralement pas d'utiliser update_all ou similaire, et vous pouvez utiliser des rappels si vous le souhaitez. Créez une migration pour renommer les colonnes en created_at et updated_at.
47

utiliser la méthode de la place 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 erreur ActiveRecordError lorsqu'elle est appelée sur de nouveaux objets ou lorsque l'attribut name est marqué comme readonly.

+0

Remarquez que pour les colonnes sérialisées, vous devrez vous-même préconfigurer la valeur. – Jared

2

Lorsque vous n'êtes pas dans une importation en bloc, vous pouvez remplacer le paramètre should_record_timestamps? méthode sur votre modèle pour ajouter de nouveaux contrôles sur quand mettre à jour la colonne updated_at.

2

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 partout où vous en avez besoin

class MyModel < ActiveRecord::Base 
    include WithoutTimestamps 

    def save_without_timestamps 
    without_timestamps do 
     save! 
    end 
    end 
end 

Ou juste un de un comme suit:

m = MyModel.find(1) 
WithoutTimestamps.without_timestamps do 
    m.save! 
end 
+1

Juste un avertissement, ce n'est pas threadsafe. Récemment mordu par ça! – Slicedpan

2

En se référant à d'autres réponses, j'ai trouvé à ma grande surprise que les timestamps de désactivation 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, il fonctionne si je désactive horodatages pour tous les modèles avec

ActiveRecord::Base.record_timestamps = false 

(Situation: modification de l'attribut created_at dans une migration)

21

Rails 5 fournit un moyen pratique de mettre à jour un enregistrement sans mise à jour de son horodatage updated_at.

Vous avez juste besoin de passer touch:false lors de la mise à jour de votre enregistrement.

>> 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 
+0

C'est de loin le moyen le plus propre de déplacer les records. –

7

Dans Rails 3+, pour un seul objet, définissez record_timestamps pour l'objet plutôt que classe. À savoir,

>> 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 ne devez pas oublier de remettre le réglage avant dans un bloc ensure.

Questions connexes