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 follow开发者_如何学JAVAing:
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.
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
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.
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
精彩评论