简体   繁体   中英

has_many association ignores restricting condition

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.

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM