getting nested attributes through strong parameters - ruby-on-rails

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

Related

Is there an easy way to remove blank objects from a has-many association?

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

Rails 5 optional has_many associations

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? }

accepts_nested_attributes_for allow_destroy doesn't work with scoped validation

I am trying to puzzle out why the accepts_nested_attributes_for will not destroy a record when it receives a hash like this:
{project_parcels_attributes"=>[{"parcel_id"=>"680060", "_destroy"=>"1"}, {"parcel_id"=>"680088"}]}
The context of use is as follows. There is a Project model:
class Project < ActiveRecord::Base
has_many :project_parcels
accepts_nested_attributes_for :project_parcels, allow_destroy: true
end
class ProjectParcels < ActiveRecord::Base
belongs_to :project
belongs_to :parcel
validates :parcel_id, uniqueness: {scope: :project_id}
end
Then I call it from a form like this:
#project.update_attributes({"project_parcels_attributes"=>[{"parcel_id"=>"680060", "_destroy"=>"1"}, {"parcel_id"=>"680088"}]})
Yet, it doesn't work. The validation stops the record from being destroyed. But when I remove validation, the record gets added multiple times.
you should add the id of the child object by an hidden_field tag
<%= f.hidden_field :id %>
and then update with the id :
{project_parcels_attributes"=>[{id: an_id, "parcel_id"=>"680060", "_destroy"=>"1"}, {id: an_id, "parcel_id"=>"680088"}]}

Changing Mongoid class name mid-production

Is this even possible?
I have a mongoid class named Magazine, with some associations as well, that I would like to re-name to Publication. Problem is that I already have a bunch of users who have already made magazines, issues and articles.
Original Magazine model:
class Magazine
# 1. Include mongoid stuff
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Slug
# 2. Define fields
field :title, type: String
field :description, type: String
field :live, type: Boolean, default: false
field :show_walkthrough, type: Boolean, default: true
# 3. Set attributes accesible
attr_accessible :title, :description, :live, :show_walkthrough, :cover_image_attributes, :logo_image_attributes
# 4. Set slug
slug :title
# 5. Set associations
belongs_to :user
has_many :issues, dependent: :delete, autosave: true
has_one :foreword, :as => :articleable, :class_name => 'Article', dependent: :delete, autosave: true
embeds_one :cover_image, :as => :imageable, :class_name => 'Image', cascade_callbacks: true, autobuild: true
embeds_one :logo_image, :as => :imageable, :class_name => 'Image', cascade_callbacks: true, autobuild: true
# 6. Accepting nested attributes
accepts_nested_attributes_for :cover_image, :allow_destroy => true
accepts_nested_attributes_for :logo_image, :allow_destroy => true
# 7. Set validations
validates_presence_of :title, :description, :cover_image, :logo_image
end
I know I can change the class-name to Publication and then do db.magazines.renameCollection( "publications" ) on the mongodb, but the associations doesn't follow along.
Any suggestions?
I looks like you have association fields in your Issue and Foreword models that probably refer to Magazine. So if you are happy enough to change the name of the class and underlying collection then renaming these association fields is your main problem. You may have something like:
class Issue
belongs_to :magazine
end
You could redefine this association as belongs_to :publication. Assuming that are happy to fix all the references to Issue#magazine in your code then your remaining problem is that your issues collection will be full of documents that have a magazine_id field instead of publication_field. You have two options to fix the database mapping.
First option is to rename the field in the database. See mongoDB : renaming column name in collection
The second option is to declare the association so that it maps to the old database field by overriding the 'foreign key' name:
belongs_to :publication, foreign_key: :magazine_id
You will have to repeat this for the Foreword model and any others that reference Magazine.
Just a heads up for polymorphism and class inheritance.
Mongoid handles inheritance and polymorphic associations by storing the class name as a document attribute.
On the class itself, this is stored as the "_type" attribute
For polymorphic associations like belongs_to :polymorphic_class mongoid adds an attribute "polymorphic_class_type", so that the class can be resolved (with Rails' .constantize) when browsing polymorphic associations.
So if you decide to change the class name, and you have inheritance or polymorphic associations, well you'll have to also rewrite all those attributes !

Nested Attributes: unwanted validation despite of reject_if : All_blank

I am new to rails so any advise is greatly appreciated.
I have a class Entry with nested attributes Addresses,
/app/models/entry.rb
class Entry < ActiveRecord::Base
has_many :addresses, :dependent => :destroy
accepts_nested_attributes_for :addresses,
:allow_destroy => true,
:reject_if => :all_blank
end
with class Addresses like this
/app/models/address.rb
class Address < ActiveRecord::Base
belongs_to :entry
validates :zip, :presence => true
end
And in the nested form I have
/app/view/entries/_form.html.slim
= simple_form_for(#entry) do |f|
= f.error_notification
- #entry.addresses.build
.form-inputs
= f.simple_fields_for :addresses do |address|
= render 'address_form', :f => address
The idea is that when the form is rendered, the 'build' will create a empty 'address' in addition to the current addresses listed in database. When the changes are saved, if the new address created is still empty, it will get rejected and not saved to the database.
However the validation in the address.rb is doing the validation before the saving, hence the user cannot proceed with the saving action. Is there anything I left out?
You might like to try explicitly naming the attributes in your address model that get checked before a new, empty one is created. Something like this:
# in app/models/entry.rb
accepts_nested_attributes_for :addresses, reject_if: lambda {|attributes| nested_address_is_empty?(attributes) }
private
def self.nested_address_is_empty?(attrs)
attrs['line_1'].blank? && attrs['line_2'].blank? && attrs['zip'].blank?
end
Try passing false as an argument to save to skip validations.

Resources