JeuWeb - Crée ton jeu par navigateur
[Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée (/showthread.php?tid=5720)



[Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée - Maz - 02-10-2011

Edit:Lisez la fin en premier.
Bonsoir, suite à mon implémentation grâce aux méthodes agrégation des class Point et Path, je suis confronté au problème d'enregistrement des modifications dans la base de donnée.

J'ai une ressource Hunting qui contient une ressource path, de type path. Le type path est composé de plusieurs objet de type point.

J'aimerais créé un cron qui exécutes une fonctions qui supprime le premier point du path, si path vaut ((3,5),(6,4),(6,2)) il deviendras: ((6,4),(6,2)). J'ai déjà coder cette fonction, qui marches parfaitement, mon problème est que lorsque j'exécute un @hunting.save, rien n'est enregistré, et pour cause, rails n'est pas au courant du changement du fait que je passes par une fonction personnalisée et non par un simple "path = newpath". J'ai donc cherché et je suis tombé sur le module Dirty, que j'ai essayé d'implémenter:
class Hunting < ActiveRecord::Base
composed_of :path, :class_name => "Path", :mapping => %w(path path), :converter => Proc.new { |path| "((6,6),(6,7))" }

def one_step_forward
path_will_change!
path.points.delete_at(0)
end
end

J'ai fait quelques tests avec la console rails dont voici les résultats:
ruby-1.9.3-rc1 :092 > @hunting = Hunting.find(1)
Hunting Load (0.5ms) SELECT "huntings".* FROM "huntings" WHERE "huntings"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Hunting id: 1, path: "((7,6),(5,4))", created_at: "2011-10-02 16:02:11", updated_at: "2011-10-02 16:46:57">
ruby-1.9.3-rc1 :093 > @hunting.one_step_forward
=> #<Point:0xb171884 @x=7, @y=6>
ruby-1.9.3-rc1 :094 > @hunting.path.to_str
=> "((5,4))"
ruby-1.9.3-rc1 :095 > @hunting.changed?
=> false

Comme vous pouvez le voir, la fonction "one_step_forward" fonctionnes bien, mais le changement n'est pas "capté" par rails.

J'ai déjà essayer tout un tas de combinaison dans mon code, mais rien n'y fait.

Une piste?

Merci.

Edit: Grrrrr, suffisait de reboot la console, 2h que je suis sur ce foutu truc! Leçon retenue: La console c'est bien, dans certains cas.
Edit²: Bon ça n'enregistres toujours pas les changements, mais c'est encore une autre histoire.


RE: [Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée - Sephi-Chan - 02-10-2011

Quand tu modifies tes classes, il faut que tu appelles la méthode reload!. C'est plus simple et rapide qu'un reboot de la console. Par contre, attention aux objets déjà instanciés : évite de réutiliser ce sont la classe a changé.

Pour ton problème :


def one_step_forward
path_will_change!
path.points.delete_at(0)
save!
end

Et ça devrait rouler. Ton objet path n'est pas une associations has_many, c'est un attribut de ton objet courant (Hunting). Il faut donc sauvegarder cet objet quand un de ses attributs change.

Enfin, il faut tester tester mais je ne suis pas certain que l'utilisation d'une méthode de Dirty soit indispensable.


RE: [Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée - Viciousity - 02-10-2011

J'allais dire pareil que Sephi, ne pas oublier le save! Smile


RE: [Résolu][Rails] Module Dirty : attribut_will_change! dans une fonction personnalisée - Maz - 03-10-2011

Non non, mais je n'oubliais pas le .save dans mes tests... Mais ça ne fonctionnes pas Wink

Le fait est que le path_was est modifié en meme temps que path lui meme... probablement donc que rails ne vois pas le changement donc n'effectue pas la mise à jour.

ruby-1.9.3-rc1 :001 > @hunting = Hunting.find(1)
Hunting Load (25.3ms) SELECT "huntings".* FROM "huntings" WHERE "huntings"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Hunting id: 1, path: "((7,6),(5,4))", created_at: "2011-10-02 16:02:11", updated_at: "2011-10-02 18:08:45">
ruby-1.9.3-rc1 :002 > @hunting.one_step_forward!
=> #<Point:0xa64c9b8 @x=7, @y=6>
ruby-1.9.3-rc1 :003 > @hunting.changed
=> ["path"]
ruby-1.9.3-rc1 :004 > @hunting.changes
=> {"path"=>[#<Path:0xa64c800 @points=[#<Point:0xa64c8f0 @x=5, @y=4>]>, #<Path:0x9466e38 @points=[#<Point:0xa64c8f0 @x=5, @y=4>]>]}
ruby-1.9.3-rc1 :005 > @hunting.save
(0.2ms) BEGIN
(0.7ms) UPDATE "huntings" SET "path" = '((7,6),(5,4))', "updated_at" = '2011-10-03 04:49:44.670416' WHERE "huntings"."id" = 1
(29.4ms) COMMIT

Edit: c'est un truc de malade ce bug... Il ne subsistes aucun path égal à ((7,6),(5,4)), d'ou rails me sort encore cette valeur?

ruby-1.9.3-rc1 :071 > @hunting = Hunting.find(1)
Hunting Load (0.5ms) SELECT "huntings".* FROM "huntings" WHERE "huntings"."id" = $1 LIMIT 1 [["id", 1]]
=> #<Hunting id: 1, path: "((7,6),(5,4))", created_at: "2011-10-02 16:02:11", updated_at: "2011-10-03 19:16:44">
ruby-1.9.3-rc1 :072 > @hunting.path
=> ((7,6),(5,4))
ruby-1.9.3-rc1 :073 > @hunting.changed?
=> false
ruby-1.9.3-rc1 :074 > @hunting.changes
=> {}
ruby-1.9.3-rc1 :075 > @hunting.one_step_forward
=> (7,6)
ruby-1.9.3-rc1 :076 > @hunting.path
=> ((5,4))
ruby-1.9.3-rc1 :077 > @hunting.changed?
=> true
ruby-1.9.3-rc1 :078 > @hunting.changes
=> {"path"=>[((5,4)), ((5,4))]}
ruby-1.9.3-rc1 :079 > @hunting.changed_attributes
=> {"path"=>((5,4))}
ruby-1.9.3-rc1 :080 > @hunting.save
(0.2ms) BEGIN
(0.5ms) UPDATE "huntings" SET "path" = '((7,6),(5,4))', "updated_at" = '2011-10-03 19:30:15.467748' WHERE "huntings"."id" = 1
(23.5ms) COMMIT
=> true


Edit²: Si j'utilises "Hunting.update(id, {:path => path})" dans ma méthode 'one_step_forward', ça fonctionnes impeccablement..."