0
votes

My rails 4 app has 3 models:

  1. Store (has_many :products)
  2. Product (has_many :product_fields and belongs_to :store and accepts_nested_attributes_for product_fields
  3. Product_fields (has a belongs_to :product)

Product only has store_id and id fields. Product_fields has string_content and text_content. Basically, right now my store model looks like:

class Store < ActiveRecord::Base
   has_many :products
   accepts_nested_attributes_for :products, :allow_destroy => true, :reject_if => :product_empty

   private

   def product_empty(a)
     a[:product_fields_attributes][:text_content].blank?
   end

end

If I create a new store without filling in text_content, the models correctly reject it (and no product or product_fields are created). Unfortunately, the problem is that if I actually do fill in text_content, then it still doesn't create it.

My rails console looks like:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"nFUg4ynXYyg99rPPPoa3uO/iHP4LT1XlOz3Vm3Zm4Z0=", "store"=>{"name"=>"Test", "products_attributes"=>{"0"=>{"type_of"=>"Book", "product_fields_attributes"=>{"0"=>{"text_content"=>"test1"}}}}}, "commit"=>"Create Store"}

My question is: How do I get the reject_if method to work on nested models? So, to be clear, I don't want to validate the nested models, I just want to not save products if it's associated product_field text_content is blank?.

2
If you mean product_fields_attributes inside your attributes, then yes it is possible. Do not forget to define accepts_nested_attributes for Porduct model if you want to use product_fields_attributes. - Farrukh Abdulkadyrov

2 Answers

2
votes

If you mean product_fields_attributes inside your attributes, then yes it is possible.

def product_empty(a)
     a[:product_fields_attributes].each do |field_id, params|
       return true if params[:text_content].blank?
     end
     return false
end

Your code didn't work because you were trying to reference :product_fields_attributes as a hash of attributes but on practice it is a hash of :id => :params pairs. Consequently where params hash contains the attributes you need.

1
votes

May be recursive validate associated model?

class Store < ActiveRecord::Base
   has_many :products, validate: true
   accepts_nested_attributes_for :products, :allow_destroy => true
end

Update 1: if required reject not valid record:

class Store < ActiveRecord::Base

  has_many :products, validate: true
  accepts_nested_attributes_for :products, :allow_destroy => true, reject_if: :invalid?

  private   
  def invalid?(attr)
    Product.new(attr).invalid?
  end    
end

class Product < ActiveRecord::Base
  belongs_to :store
  has_many :product_fields, validate: true

  validates :product_fields, :presence => true
  accepts_nested_attributes_for :product_fields, :allow_destroy => true
end

class ProductField < ActiveRecord::Base
  belongs_to :product

  validates :string_content, :presence => true
  validates :text_content, :presence => true
end

or custom validation method in ProductField model, like:

validate :require_all_fields 
def require_all_fields
  errors.add(:base, "required") unless ....
end