using :reject_if to check for empty field - ruby-on-rails

In Rails 2.3.5 model I am using
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }
But its rejecting if there is the textbox is not empty..
How can I make it to reject only if there is nothing entered into the textbox ?

Are you confusing reject_if with record validation? The reject_if merely tells the app to ignore that set of nested attributes if a condition is true. In your case, the question's attributes will be ignored if the question's content is blank. If you want to validate or otherwise ensure that the question record(s) have a non blank value for content, you'd put validation in your question model.
You also might consider changing lambda{} to proc{}.

reject if will save the parent object and any other amount of child objects rejecting only those that fail the reject_if condition. If this is what you want then it is fine, i suggest debugging a little bit, put in a print statement or something, maybe
lambda { |a| puts a.inspect; a[:content].blank? }
If you want the whole nested object to save all at once, then use validations.

Related

What is the rationale for `reject_if`?

I've come across reject_if in cocoon's README, and also in the documentation for Nested Attributes. What is the rationale for using reject_if when the associated active record objects can determine whether they're valid or not?
For nested objects, you may not want to attempt to submit a record that is :all_blank or for any other reason you may want to check on. The point being, an empty or incomplete (in some way) object can, this way, simply not be built / added to the nested objects collection.
Validations serve a different purpose. If an empty object, say, fails validation then the whole form submit will fail. The reject_if approach allows submission to succeed in such a case by removing the object from consideration before validations fire.
The Rails guides has a description of the rationale for :reject_if, though it doesn't explicitly compare this option to just validating the sub-objects:
9.5 Preventing Empty Records
It is often useful to ignore sets of fields that the user has not
filled in. You can control this by passing a :reject_if proc to
accepts_nested_attributes_for. This proc will be called with each
hash of attributes submitted by the form. If the proc returns false
then Active Record will not build an associated object for that hash.
The example below only tries to build an address if the kind
attribute is set.
class Person < ActiveRecord::Base
has_many :addresses
accepts_nested_attributes_for :addresses, reject_if: lambda {|attributes| attributes['kind'].blank?}
end
As a convenience you can instead pass the symbol :all_blank which
will create a proc that will reject records where all the attributes
are blank excluding any value for _destroy.

Validates and nested forms

my ruby on rails 3.0.3 app display an empty address form when showing the cart to a customer.
The addresse module ask the presence of all fields :
validates :nom,:prenom,:adresse,:code_postal,:ville,:email, :presence => true
If I validate an empty form it works despite validate condition.
I complete the forms, go to next page and comes back to the now populated creation form. Now if i remove a field the valiates is taken into account.
Here is my empty address creation code for the nested form in the show action :
if (#cartshowed.adresse_client.nil?)
#cartshowed.build_adresse_client
end
I guess that when usind the empty address validation is ignored, but as soon as i validate data for an already valid adress it works.
How can i have validation working when i create the address, and not only for edition ?
PS : The edition/creation is done on the same page through the same controllers. Edition was not intended to exist but it works.
EDIT : After several try i think my problem is that creating adresse through nested forms completly overiddes validates field in address.
How can i kee validates restriction in a nested form?
If Addresse is a nested attribute (i.e. Cart has_one Address), perhaps you should use the accepts_nested_attributes_for which allows you to add a :reject_if Proc.
accepts_nested_attributes_for :addresse, :reject_if => :any_blank
I couldn't give a better example than Ryan Daigle:
http://archives.ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for
It seems that as soon as i use reject_if the validation of my children model is not totaly taken into account. Removing the reject_if resolved all my problems. Now an empty form or a form not conform to the validates requirement is correctly rejected at the update_attributes step in the controller.

Rails 3.0.11 : attributes= on a parent model will call validations on nested models

I'm having an issue working with Rails 3.0.11 on a project.
I have a parent model called Candidate which has_one many nested_models.
I use nested_forms to save candidates in 2 ways :
-> without validations => I need to save "work in progress"
-> with validations => before going to next step
My issue concerns the first point : "without validations". I can't use update_attributes to mass-assign in my controller because it calls validations. I've tried a simple #candidate.attributes = params[:candidate] but it's wrong too because it will calls validation on nested model (through a classic save).
My problem is that even if I don't save my parent model (I'm just doing a mass-assign), nested model are saved and validations are triggered...
Am I doing something wrong ?
Thanks for your help.
Regards,
Yoann.
There seems to be several ways to not validate objects, though I don't know for sure how they behave when using nested attributes:
http://guides.rubyonrails.org/active_record_validations_callbacks.html
Since you write that you have tried bypassing validation by using update_attributes, perhaps you should try conditional validation instead on your nested model. Something like this maybe:
validates :some_stuff, :presence => true, :if => Proc.new { |record| record.parent.complete? }

How do I change an ActiveRecord from marked to be saved to make sure it does not get saved, from within the model itself?

How do I change an AcriveRecord from marked to be saved to make sure it does not get saved, from within the model itself?
Considering I can have a method run by a hook in activerecord, such as: before_save
for (hypothetical) example:
before_save :ignore_new_delete_exisiting_if_blank(self.attribute)
def ignore_new_delete_exisiting_if_blank(attribute)
self.do_not_save_me! if attribute.blank?
#what is that magic "do_not_save_me" method?
#Is there such thing, or something to achieve the same thing?
end
Update
My particular use case requires that no errors be thrown and other models to continue to be saved, even if this one will not. I should explain:
I am using model inheritance, and I am having an issue with figuring out how to let save the parent model, but if the child model instances are blank, (no values exist in certain attributes) they should not be persisted; however, the parent should still be persisted. This scenario does not let me make use of validations on the child model as that would block the parent from being persisted as well...
Your method should just return false to make it does not save.
Or you set the errors, which will allow to be more descriptive.
For example:
def ignore_new_delete_exisiting_if_blank_attribute
if attribute.blank?
errors.add(:base, "Not allowed to save if attribute is blank.")
end
end
Note that you cannot send parameters to a before_save. If you just want to make sure a record is not saved when an attribute is not present, you should use
validates_presence_of :attribute
[UPDATE]
When saving a parent model with children, you have to do something like accepts_nested_attributes_for, and in that call, you can specify which attributes must be given or when a child-record is ignored.
For example
accepts_nested_attributes_for :posts, :reject_if => proc { |attributes| attributes['title'].blank? }
will not save a post if the title is blank.
Hope this helps.
The "magic" is that when you return false from the method, the record won't be saved.
In your case:
def ignore_new_delete_exisiting_if_blank(attribute)
attribute.present?
end

stop record from being saved if all empty strings in rails

I currently have a nested forms model. The nested forms for the paperclip attachments work fi and don't populate the DB with blanks, but another one I have for quotes always saves one blank quote along with my main model when I create a new one. How can I just have it silently fail and bypass writing this to the db? It's an optional field so I don't want to give them an error.
Use the following option on accepts_nested_attributes
accepts_nested_attributes_for :quotes, :reject_if => :all_blank
If you want to be more specific about when the record is considered blank, :reject_if also can take a proc.

Resources