Rails relationships that is [image: :)]
I am doing something wrong, and can’t figure out what and where.
I have 3 models - Command, Contact, and a joined CommandsContact via
has_many through relationship, because commands_contacts table holds an
extra column - notification_type, which could be either set to host of
*service. *
*Models *
contact.rb
This one is a special case, because it has 2 extra “virtual”
relationships
:host_notification_commands and :service_notification_commands, which
gives
me an ability to selectively get either host or service commands for
a
user (contact) like this:
Contact.first.host_notification_commands or
Contact.find(3).service_notification_commands etc.
class Contact < ActiveRecord::Base
has_many :commands_contacts, :inverse_of => :contact
has_many :commands, :through => :commands_contacts
has_many :host_notification_commands, -> { where commands_contacts: {
:notification_type => ‘host’ } },
:through => :commands_contacts,
:class_name => ‘Command’,
:source => :command
has_many :service_notification_commands, -> { where commands_contacts:
{ notification_type: ‘service’ } },
:through => :commands_contacts,
:class_name => ‘Command’,
:source => :command
accepts_nested_attributes_for :host_notification_commands
accepts_nested_attributes_for :service_notification_commands
end
command.rb
class Command < ActiveRecord::Base
has_many :commands_contacts, :inverse_of => :command
has_many :contacts, :through => :commands_contacts
accepts_nested_attributes_for :commands_contacts
end
commands_contracts.rb
class CommandsContact < ActiveRecord::Base
belongs_to :command
belongs_to :contact
accepts_nested_attributes_for :command
accepts_nested_attributes_for :contact
end
So far. So good. This works as expected (i think?) as I am able to
manually
create relationships, as long as i have a contact and a command already.
contact = Contact.first
command = Command.find(7)
contact.host_notification_commands << command
Aaand after this things start to go down south, because a Controller,
strong_parameters and accepts_nested_attributes_for come into play, and
this is where I fail.
My assumption is that Rails will be able to handle this for me and
establish the relationship, right?
def create
contact = Contact.new safe_params
contact.saveend
Because I use accepts_nested_attributes_for, I have to append
_attributes to
the names of nested objects, right? So i do a simple re-assignment here
and
then permit them with strong_parameters.
privatedef safe_params
params[:contact][:host_notification_commands_attributes] =
params[:contact][:host_notification_commands]
params[:contact][:service_notification_commands_attributes] =
params[:contact][:service_notification_commands]
params.require(:contact)
.permit(:contact_name,
:host_notification_commands_attributes => [ :id, :command_name,
:command_line, :command_description ],
:service_notification_commands_attributes => [ :id,
:command_name, :command_line, :command_description ])
As far as I understand, this is all that needs to be done and Rails
should
handle the rest, right? The problem is that it does not even try to to
establish a relationship. It does a SELECT and immediately fails.
When I try to create a new record, it fails with:
ActiveRecord::RecordNotFound (Couldn’t find Command with ID=1 for
Contact
with ID=):
Because it hasn’t yet created a user a hasn’t established a
relationship.
When I try to edit and existing contact and establish a relationship
with
existing command, it fails with
(0.1ms) BEGIN
Command Load (0.2ms) SELECT commands
.* FROM commands
INNER JOIN
commands_contacts
ON commands
.id
=
commands_contacts
.command_id
WHERE commands_contacts
.contact_id
= 3 AND
commands_contacts
.notification_type
= ‘host’ AND commands
.id
= 1
(0.1ms) ROLLBACK
Completed 404 Not Found in 6ms
ActiveRecord::RecordNotFound (Couldn’t find Command with ID=1 for
Contact
with ID=3):
Uhm… Of course this relationship record is not found. I am trying to
create it! Why does it run SELECT instead of UPDATE / INSERT ?
So, something tells me I have this relationship defined incorrectly
somewhere in my models… but where? How do i troubleshoot this?