Nested attributes with polymorphic association in Rails 5 - ruby-on-rails

I've created an Address model with a polymorphic association, I am trying to save to it though nested attributes of a client model but I am getting Address addressable must exist in the #client.errors.
Models:
class Client < ApplicationRecord
has_one :address, as: :addressable, dependent: :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
end
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
Controller:
class ClientsController < ApplicationController
def new
#client = Client.new
#client.create_address
end
def create
#client = Client.new(client_params)
if #client.save
...
else
...
end
end
private
def client_params
params.require(:client).permit(:first_name ,:last_name, :company, address_attributes: [:line1, :line2, :line3, :city, :state_province, :postal_code, :country])
end
end

You should add the inverse_of key on your belongs_to relation, e.g. on your Address class:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true, inverse_of: :addressable
end
This will save the nested address correctly as Rails will now correctly know what to assign in the addressable.
Don't use the optional key unless the addressable is truly optional.

belongs_to :xx, polymorphic: true, optional: true

Also
optional: true
tricking the problem, you may keep relationships mandatory by breaking creation in controller in two steps.
def client_params
params.require(:client).permit(:first_name ,:last_name, :company)
end
def address_params
params.require(:client).require( :address_attributes).permit(:line1, :line2, :line3, :city, :state_province, :postal_code, :country )
end
def create
#client = Client.new(client_params)
if #client.save
#client.create_address( address_params )
...
this may look uglier but it keeps relations safer.

Related

Error when submitting form: Nested attributes unpermitted parameters

I've tried the solutions on this other stack overflow question but they aren't working.
I'm getting this error when submitting my form: Unpermitted parameter: organization_required_fields
Any help would be appreciated.
I have the following models:
class Organization < ActiveRecord::Base
belongs_to :user
has_many :organization_required_fields
has_many :fields, through: :organization_required_fields
accepts_nested_attributes_for :organization_required_fields, allow_destroy: true
end
class OrganizationRequiredField < ActiveRecord::Base
belongs_to :organization
belongs_to :field
end
class Field < ActiveRecord::Base
has_many :organization_required_fields
has_many :organizations, through: :organization_required_fields
end
My controller:
def update
...
#organization.update(organization_params)
...
end
private
def set_organization
#organization = Organization.find_by_id(params[:id])
...
end
def organization_params
params.require(:organization).permit(:name, :user_id, organization_required_fields_attributes: [:id, :organization_id, :field_id, :_destroy])
end
My form view
...
= f.select :organization_required_fields, options_for_select(#fields.collect {|rf| [ rf.name.titleize, rf.id ] }, #organization.fields.collect{ |orf| orf.id }),{ :prompt => "Please select"},{ :multiple => true, :size => 15 }
...
I actually changed a lot by following this rails cast
I also had to change the organization_params to
params.require(:organization).permit(:name, :user_id, { field_ids: []})
You need to use fields_for in your form.

Ruby on Rails - Nested attributes not working

I have this two simple models:
class Address < ApplicationRecord
belongs_to :community
geocoded_by :full_address
validates :address, :city, :province, :country, presence: :true
validates :postalcode, presence: true, postalcode: true
after_validation :geocode
def full_address
[address, province, postalcode, country].compact.join(', ')
end
end
And
class Community < ApplicationRecord
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
has_many :community_people, dependent: :destroy
has_many :people, through: :community_people, source: :user
validates :name, :address, :administrators, presence: true
# ...
end
I'm trying to create some stub Communities using a seed.rb:
def self.create_community(administrators: [], residents: [], address: {})
Community.create(
name: Faker::Name.name,
administrators: administrators,
residents: residents,
address_attributes: address
)
#communities += 1
end
But I always get:
ActiveRecord::RecordInvalid: Validation failed: Address community must exist
PS: Also tried using "community.create_address" and other things.
To only way I could get it to work was:
Saving Community (with no address)
Saving Address referencing community_id.
But I had to hack my Model and remove :address from the validates method in community.rb.
So how can I make accepts_nested_attributes_for work?
I think you are using Rails 5. This issue is because of feature change in Rails 5. For more info read this.
You should try adding optional: true to belongs_to relationship. Like this.
class Address < ApplicationRecord
belongs_to :community, optional: true
end

Rails 4 validation error with has_many through association

I have troubles creating the records in an association with rails 4. It's basically an association between Entry and Author, with a join table in the middle called AuthorsEntry. The schema is the following:
class Entry < ActiveRecord::Base
validates :name, presence: true
validates :from, presence: true
validates :to, presence: true
belongs_to :event
has_many :authors, through: :authors_entry
has_many :authors_entry
class AuthorsEntry < ActiveRecord::Base
validates :author, presence: true
validates :entry, presence: true
belongs_to :author
belongs_to :entry
end
class Author < ActiveRecord::Base
belongs_to :event
has_many :entries, through: :authors_entry
has_many :authors_entry
validates :name, presence: true
validates :event, presence: true
end
In my program_entries_controller.rb I have the following methods:
def create
#program_entry = Entry.new(program_entry_params)
author_ids_params.each do |id|
#program_entry.authors << AuthorsEntry.build(author_id: id)
end
#program_entry.event = #event
if #program_entry.save
flash[:notice] = t(:program_entry_created_successfully)
redirect_to organizer_event_program_entry_path(#event, #program_entry)
else
render :new
end
end
def program_entry_params
params.require(:program_entry).permit(
:name, :abstract, :'from(1i)', :'from(2i)', :'from(3i)',
:'from(4i)', :'from(5i)', :'to(1i)', :'to(2i)', :'to(3i)', :'to(4i)',
:'to(5i)'
)
end
def author_ids_params
params.require(:program_entry).permit(:author_ids => [])
end
I already have the authors saved in my database, the create action should just add a new record for the Entry model and the association (authors_entry) table. But when I try saving the entry it always returns "is_invalid" over authors_entry.
The join table should be named AuthorEntries to follow rails convention.

Can't mass-assign protected attributes:

Have tried the solutions for this common error in stackoverflow but none of them seem to work in this case, it might be that I already created an address field on the property before. I keep getting the mass assignment error.
Any help appreciated.
Address.rb
class Address < ActiveRecord::Base
attr_accessible :addressable_id, :addressable_type, :city, :county, :postcode, :street1, :street2
belongs_to :addressable, :polymorphic => true
end
Property.rb
class Property < ActiveRecord::Base
attr_accessible :name, :addresses_attributes
belongs_to :user
has_one :address, :as => :addressable
accepts_nested_attributes_for :address
validates :name, presence: true, length: { maximum: 200 }
validates :address, presence: true
validates :user_id, presence: true
end
Property Controller
class PropertiesController < ApplicationController
before_filter :authenticate_user!
before_filter :correct_user, only: :destroy
def index
#property= Property.all
end
def create
#property = current_user.properties.build(params[:property])
if #property.save
flash[:success] = " Property Added"
redirect_to root_path
else
render 'edit'
end
end
def new
#property = Property.new
#property.build_address
end
You should add
accepts_nested_attributes_for :address
and change
attr_accessible :name, :address_attributes
and if it doesn't work change both address to addressable

Has a relationship through four models?

I'm having trouble setting up this association between my models.
A User has many Accommodations, and Accommodations have one User.
Accommodations have many Notifications, and Notifications have one Accommodation.
Requests have many Notifications.
How can I make it so that I can get all of the Requests for a given User ( that is, User -> Accommodations (each) -> Notification -> Request)?
Update:
Here's my current controller file:
class PanelController < ApplicationController
before_filter :login_required
def index
#accommodations = current_user.accommodations.all
#requests = Array.new
#accommodations.each do |a|
a.notifications.each do |n|
#requests << Request.where('id' => n.request_id)
end
end
end
end
And models:
models/user.rb
class User < ActiveRecord::Base
[snip]
has_many :accommodations
has_many :notifications,
:through => :accommodations
end
models/accommodation.rb
class Accommodation < ActiveRecord::Base
validates_presence_of :title, :description, :thing, :location, :spaces, :price, :photo
attr_accessible :photo_attributes, :title, :description, :thing, :location, :spaces, :price
has_one :photo
has_many :notifications
belongs_to :user
accepts_nested_attributes_for :photo, :allow_destroy => true
end
models/notification.rb
class Notification < ActiveRecord::Base
attr_accessible :accommodation_id, :request_id
has_one :request
belongs_to :accommodation
end
models/request.rb
class Request < ActiveRecord::Base
belongs_to :notifications
attr_accessible :firstname, :lastname, :email, :phone, :datestart, :dateend, :adults, :children, :location, :status
validates_presence_of :firstname, :lastname, :email, :phone, :datestart, :dateend, :children, :adults, :location
end
Something like this should work:
#reqs = []
#user.accommodations.all.each do |a|
#reqs << a.notification.request
end
Assuming this is correct:
class User
has_many :accommodations
end
class Accommodation
belongs_to :user
has_many :notifications
end
class Notification
belongs_to :accomodation
belongs_to :request
end
class Request
has_many :notifications
end
Using has_many :through will not work for multiple models, as seen here: Ruby-on-Rails: Multiple has_many :through possible?
But you can do something like this in your user model:
class User
has_many :accommodations
has_many :notifications,
:through => :accommodations
def requests
self.notifications.all.collect{|n| n.request }
end
end

Resources