2009-12-14 5 views
0

Je suis à la recherche d'un moyen propre pour filtrer les enfants d'un parent dans une relation has_many sans frapper la base de données et donc rechargeant le point de vue de la db des objets en arrière dans l'application.ActiveRecord: filtrage des enfants sans frapper la base de données

Par exemple:

class Parent < ActiveRecord::Base 
    has_many :children, ... 
    ... 
end 

Si je comprends bien (corrigez-moi si je me trompe) est que

parent.children.find_all_by_attr('foo') 

retourne tous les enfants du parent qui ont une valeur attr de 'foo' dans le db mais comme il retourne à nouveau dans la base de données, tous les enfants dont la valeur attr a été définie sur foo avant d'être sauvegardés verront leurs valeurs db restaurées, écrasant ainsi les modifications.

J'ai piraté autour de cela avec

parent.children.reject { |child| child.attr != 'foo' } 

mais cela semble très bâclée et plus difficile à lire. Est-ce que quelqu'un a une suggestion plus propre sur la façon de faire cela?

Répondre

3

Après avoir fait quelques farfouillé, on dirait qu'il est un peu plus compliqué que cela. Mon poking a fait le tour comme ceci:

  • J'ai créé une paire de modèles, Parent et enfant avec une has_many relation dans un rail app jetables.
  • J'ai ouvert script/console et poussé autour.

J'ai créé un nouveau parent avec un enfant et les délivra

>> p = Parent.new;p.children << Child.new(:foo=>'bar');p.save 
=> true 

Voir l'enfant est dans la db et trouvable by_foo

>> p.children.find_by_foo('bar') 
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05"> 

j'ai ajouté un autre enfant à la collecte, il apparaît dans p.children mais pas dans les méthodes de collecte qui touchent la base de données.

>> p.children << Child.new(:foo=>'bar') 
=> [#<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">, #<Child id: 2, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:25", updated_at: "2009-12-14 22:08:25">] 
>> p.children.find_by_foo('bar') 
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05"> 

Je change l'enfant qui est dans le db.

>> p.children[0].foo = 'baz' 
=> "baz" 

Lorsque je le cherche, il me donne la version db.

>> p.children.find_by_foo('bar') 
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05"> 

Mais, la collection locale est inchangée.

>> p.children 
=> [#<Child id: 1, foo: "baz", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">, #<Child id: 2, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:25", updated_at: "2009-12-14 22:08:25">] 

Donc, si vous enregistrez de nouveau p, il transmettra les modifications.Si vous voulez obtenir tous les objets d'association locale, y compris ceux qui ont été modifiés, vous ne pouvez pas utiliser les moteurs de recherche ActiveRecord car ils utilisent la méthode db, utilisez plutôt les méthodes de tableau comme vous l'avez fait plus haut. Bien, en utilisant find_all ou select serait plus facile à comprendre

parent.children.select{|c| c.attr == 'foo'} 
0

Vous pouvez faire le contraire de reject, qui est find_all:

parent.children.find_all {|child| child.attr == 'foo' } 
Questions connexes