Pregunta

I'm working on a Rails 3.0.x application (actually it's Hobo 1.3.x but that's not material to this question). Among the models, there are GraphPanes, GraphLabels, and LabelSets. A GraphPane can have GraphLabels and LabelSets. GraphLabels can belong to GraphPanes or LabelSets, but not both. So if a GraphLabel belongs to a LabelSet, I'd like to keep it from being associated to a GraphPane.

I am trying to enforce that with this code in the GraphPane model:

has_many :graph_labels, :conditions => 'label_set_id = NULL'

However, I'm still able to associate GraphLabels with not-null label_set_id with GraphPanes. Why? How can I stop this?

This question is superficially similar, but my relationship isn't polymorphic, so the nominal solution there doesn't help me.

¿Fue útil?

Solución

The functionality of :conditions on has_many is to filter the results that are passed back via the graph_labels, not to protect objects from being added to the association.

If you add a graph_label with no label_set_id, the association will build, but if you then ask for graph_pane.graph_labels, it will not return that non-condition-matching graph_label.

The has_many/belongs_to relationship is saved on the belongs_to model, graph_label, and so the parent/has_many/graph_pane does not stop the graph_label from writing whatever it wants to its graph_pane_id attribute. This delegation of responsibility is correct, although frustrating, I agree.

Now, as for how to stop this, I'm not sure. It sounds like you need some sort of validation on the graph_label object, something along the lines of not allowing a graph_pane_id to be set on a graph_label if that graph_label's label_set_id is nil. Since the has_many/belongs_to relationship is saved on the graph_label, you should write the validation on the graph_label. That way, the graph_label will not be able to be saved with a new graph_panel_id unless it fulfills the condition.

Thoughts? Questions?

Reference:
has_many

Alternate Solution

I've reread your question and I think want you want here is a polymorphic association.

def GraphPane < ActiveRecord::Base
  has_many :label_sets
  has_many :graph_labels, as: :parent
end

def LabelSet < ActiveRecord::Base
  belongs_to :graph_pane
  has_many :graph_labels, as: :parent
end

def GraphLabel < ActiveRecord::Base
  belongs_to :parent, polymorphic: true
end

That way, a GraphLabel can only have a single parent, which is what your “spec” above requires. Is there any reason not to implement the relations in this way?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top