app/models/donor.rb
has_many :donor_relationships
accepts_nested_attributes_for :donor_relationships, :allow_destroy => true
app/models/donor_relationship.rb
belongs_to :donor, optional: true
I am using f.fields_for in donor form and creating donor and donor_relationships both.
donor_relationships is not required must. Issue I face is that when if I not add any donor_relationships then empty record of donor_relationship is created with donor id. In rails 4 not like this happen.
How can I fix this?
accepts_nested_attributes_for ignore blank values
You can add a reject_if conditional to the accepts_nested_attributes method. Assuming your donor_relationship has an attribute of name (you can go with relationship_id or whatever attribute makes sense):
accepts_nested_attributes_for :donor_relationships,
:allow_destroy => true,
:reject_if => lambda { |c| c[:name].blank? }`
You can use reject_if option:
accepts_nested_attributes_for :donor_relationships,
allow_destroy: true,
reject_if: proc { |attributes| attributes['important_field'].blank? }
Related
I got the following models:
class Course < ApplicationRecord
has_many :external_ids, as: :identifiable, dependent: :destroy, validate: true
accepts_nested_attributes_for :external_ids
end
and this one:
class ExternalId < ApplicationRecord
belongs_to :identifiable, polymorphic: true
validates :name, presence: true, uniqueness: true
validates :identifiable, presence: true, on: :create
end
Because of a nested form in the course form-view it's possible that a blank object of an external id will be saved. I'd like to remove these blank objects. With "blank object" I mean an ExternalId which is a new record and has a blank name. Currently I do that as follows:
#course.attributes = course_params
## SNIP - workaround to fix validations
external_ids = []
#course.external_ids.each do |ext_id|
external_ids << ext_id unless(ext_id.new_record? && ext_id.name.blank?)
end
#course.external_ids = external_ids
## SNAP - workaround to fix validations
#course.save
But this is a lot of code for a very simple task. Is there any function for that? destroy_if doesn't exists for an association, only for arrays.
Thanks you!
You can use accepts_nested_attributes_for with such key
accepts_nested_attributes_for :external_ids, reject_if: proc { |attributes| attributes['name'].blank? }
From docs:
You may also set a :reject_if proc to silently ignore any new record hashes if they fail to pass your criteria
I have a model Actes and a model Keywords that are habtm in relation to each other.
When sending the new acte form to the server, I can't get through the strong parameters.
This is in params[:acte] :
"acte"=>{
"biblio_id"=>"1",
"acte_numero"=>"12",
"keywords_attributes"=>{"0"=>{"keyword"=>"attestation, "}},
"texte"=>"<p>test</p>",
"complement"=>""
}
model acte.rb contains:
has_and_belongs_to_many :keywords
belongs_to :user, optional: true
belongs_to :biblio, optional: true
belongs_to :archive, optional: true
has_many :comments
accepts_nested_attributes_for :keywords, allow_destroy: true,
Note: if I add reject_if: :all_blank to accepts_nested_attributes_for, then the form doesn't get sent at all.
This is in acte_controller:
def params_acte
params.require(:acte).permit(:biblio_id,
:acte_numero,
:keywords_attributes =>[:keyword],
: resume,
# cut for brievity
This provokes a syntax error, unexpected ',', expecting => :resume, ^
You should add the keywords_attributes at last.
def params_acte
params.require(:acte).permit(:biblio_id,
:acte_numero,
:resume,
# All other model attributes
:keywords_attributes =>[:keyword],
This will work.
NOTE: Always add nested attributes at the ending
So I have many polymorphic children for a Profile object. The models are designed to destroy after_save if the specific Object's field is blank.
But for accept_nested_attributes I don't want to create the child object in the first place if it's blank. But if I leave the reject_if statement then the user no longer has the ability to empty the field on UPDATE because the reject_if rejects their blank input.
accepts_nested_attributes_for :socials, reject_if: proc { |att| att['username'].blank? }
accepts_nested_attributes_for :phones, reject_if: proc {|att| att['number'].blank? }
accepts_nested_attributes_for :websites, reject_if: proc {|att| att['url'].blank? }
So I want to reject_if: { ... }, on: :create. But that doesn't seem to work.
You can create a method and instead of sending a proc into the reject_if option, which is the same, it is just more readable, so the code would look like:
accepts_nested_attributes_for :socials, reject_if: :social_rejectable?
private
def social_rejectable?(att)
att['username'].blank? && new_record?
end
You can just repeat the methods and then clean it up with some metaprogramming or add the new_record? method on the proc
accepts_nested_attributes_for :socials, reject_if: proc { |att| att['username'].blank? && new_record?}
In my model I have
has_one :order, dependent: :destroy
accepts_nested_attributes_for :order, reject_if: lambda { |order| order[:description].blank? }, allow_destroy: true
For some reason, although the reject_if is tested and returns true (I checked that with the debugger), the nested order is not destroyed.
There is a lot of writing about this phenomenon on the internet, but I can't find a solution.
Does anybody know how to solve this?
I finally created an intelligent "reject_if" setting the destroy flag on this specific occasion, as described in Destroy on blank nested attribute, but, to my own norms, this is not very "ruby", so can't imagine there is no better solution...
accepts_nested_attributes_for :order, allow_destroy: true, reject_if: lambda { |attributes|
exists = attributes['id'].present?
empty = attributes[:description].blank?
attributes.merge!({_destroy: 1}) if exists and empty
return (!exists and empty)
}
From the nested_attributes API
You may also set a :reject_if proc to silently ignore any new record hashes if they fail to pass your criteria.
params = { member: {
name: 'joe', order_attributes: [
{ description: 'Kari, the awesome Ruby documentation browser!' },
{ description: 'The egalitarian assumption of the modern citizen' },
{ description: '', _destroy: '1' } # this will be ignored
]
}}
Any hash with a blank description will be completly ignored, even if it has the _destroy flag.
If you want to remove records with a blank description, I can think of two solutions
Option 1: remove them with a callback at your model:
before_save :remove_orders_without_description
def remove_orders_without_description
orders.select{|o| o.description.blank?}.each(&:delete)
end
Option 2: Remove the reject_if option at the model definition and use JS at the view to set the _delete attribute appropriately
try this
accepts_nested_attributes_for :order, reject_if: lambda { |order| order[:_destroy].blank? && order[:description].blank? }, allow_destroy: true
Here's the (simplified) code:
class Biosimilar::AdverseEvent < ActiveRecord::Base
attr_accessibile :adverse_event_med_conds_attributes
has_many :adverse_event_med_conds,
:class_name => 'Biosimilar::AdverseEventMedCond',
:dependent => :destroy
has_many :med_conds,
:class_name => 'Biosimilar::MedCond',
:through => :adverse_event_med_conds
accepts_nested_attributes_for :adverse_event_med_conds,
:allow_destroy => true,
:reject_if => proc { |attributes| attributes.any? {|k,v| v.blank?} }
end
When the form is submitted, the record is created on "adverse_event_med_conds" table even if the user leaves the "med_cond_id" field EMPTY. The reject_if doesn't work!
Any suggestions?
Ok, forget it. The above code is correct! The problem was in the controller, I accidentally left in the "show" method the following lines:
if #adverse_event.adverse_event_med_conds.size == 0
#adverse_event.adverse_event_med_conds.build
end
...and the "build" call was the one that caused record creation.