auralbee
auralbee

Reputation: 8841

How to avoid saving a blank model which attributes can be blank

I have two models with a HABTM association, let´s say book and author.

class Book
  has_and_belongs_to_many :authors
end

class Author
  has_and_belongs_to_many :books
end

The author has a set of attributes (e.g. first-name,last-name,age) that can all be blank (see validation).

validates_length_of :first_name, :maximum => 255, :allow_blank => true, :allow_nil => false

In the books_controller, I do the following to append all authors to a book in one step:

@book = Book.new(params[:book])
@book.authors.build(params[:book][:authors].values)

My question: What would be the easiest way to avoid the saving of authors which fields are all blank to prevent too much "noise" in the database?

At the moment, I do the following:

validate :must_have_some_data

def must_have_some_data
  empty = true
  hash = self.attributes
  hash.delete("created_at")
  hash.delete("updated_at")
  hash.each_value do |value|
    empty = false if value.present?
  end

  if (empty)
    errors.add_to_base("Fields do not contain any data.")
  end
end

Maybe there is an more elegant, Rails-like way to do that.

Thanks.

Upvotes: 1

Views: 1537

Answers (3)

14113
14113

Reputation: 66

You can change one line :)

def create
  book = Book.new(params[:book])
  params[:authors].each do |author|
    # book.authors.build(author) unless author.attributes.each{|k,v| !v.blank?}.empty?
    book.authors.build(author) unless author.all? {|key,val| val.empty?}
  end
  if book.save
    ...
  end
end

Upvotes: 1

fl00r
fl00r

Reputation: 83680

A little shorter

def must_have_some_data
  hash = self.attributes
  hash.delete("created_at")
  hash.delete("updated_at")
  errors.add_to_base("Fields do not contain any data.") if hash.select{|k,v| !v.blank?}.empty?
end

Actually I think, that you should validate not all attributes, but just specific attributes, which you are expecting to presence

def must_have_some_data
  valid_fields = ['first_name', 'second_name', 'last_name']
  errors.add_to_base("Fields do not contain any data.") if self.attributes.select{|k,v| valid_fields.include? k and !v.blank?}.empty?
end

UPD In this situation you should also check authors fields in controller. So your authors fields must be in separate params group.

def create
  book = Book.new(params[:book])
  params[:authors].each do |author|
    book.authors.build(author) unless author.attributes.each{|k,v| !v.blank?}.empty?
  end
  if book.save
    ...
  end
end

Upvotes: 1

inkdeep
inkdeep

Reputation: 1127

put this in the books model:

validates_associated :authors, :on => :create

Unless you want invalid author objects to be silently ignored but not saved. Then the current solution is one way of solving it.

What version of rails are you using? accepts_nested_attributes_for might be of use in this situation.

Upvotes: 1

Related Questions