Rails validation for a has_many association

has-many, ruby-on-rails, validation

Solution

Not sure why you need to do such a thing, but anyway, how about doing this?

class Parent < ActiveRecord::Base

  CHILDREN_TYPES = %w[bookmark_id history_id window_id]
  CHILDREN_TYPES.each{ |c| attr_accessor c }

  has_many :children

  before_validation :assign_children
  validate :ensure_has_proper_children

private

  def assign_children
    CHILDREN_TYPES.each do |t|
      children << Child.find(send(t)) unless send(t).blank?
    end
  end

  def ensure_has_proper_children
    # Test if the potential children meet the criteria and add errors to :base if they don't
  end
end

Controller:

...
p = Parent.new(params[:data])
p.save!
...

As you can see, I moved all the logic to model at the first place. Then, there is a two-step process for saving children. First, we assign children to the parent and then we validate if they meet the required criteria (insert your logic there).

Sorry for being short. I'll answer any further questions if necessary.

Problem

I am having trouble with validations on a has_many relationship where the children exist, but the parent doesn't. However, when creating/saving the parent object, I want to ensure that specific children (with certain attributes) have already been saved. There is a `Parent` object that `has_many` `Child` objects. The `Child` objects are persisted into the database first, and thus don't have any reference to the parent. The association structure is: ``` Parent - has_many :children Child - someProperty: string - belongs_to: parent ``` For example, there are three child objects: ``` #1 {someProperty: "bookmark", parent: nil} #2 {someProperty: "history", parent: nil } #2 {someProperty: "window", parent: nil } ``` A parent is valid only if it contains child objects with someProperty `history` and `window`. I am setting up the parent inside the controller as: ``` p = Parent.new(params[:data]) for type in %w[bookmark_id history_id window_id] if !params[type].blank? p.children << Child.find(params[type]) end end // save the parent object p now p.save! ``` When the children are assigned to the parent with `<<`, they are not saved immediately as the parent's id does not exist. And for the parent to be saved, it must have at least those 2 children. How could I solve this problem? Any input is welcome.

Original source