I have an application that tracks services (servers) with IP addresses. I'm trying to set it up so that when I create a new service the following happens:
As I understand, I think this should be possible with either nested attributes or virtual attributes... But I am not sure.
I have models like so:
class Service < ActiveRecord::Base
has_many :ips
attr_accessor :service_ips
end
class Ip < ActiveRecord::Base
belongs_to :service
end
Controller like so:
class ServicesController < ApplicationController
def new
@available_ips = Ip.where(:service_id == nil)
end
And a view like so:
<%= form_for(@service) do |f| %>
<%= f.label :service_ips %>
<%= f.collection_select(:service_ips, @available_ips, :id, :address, { }, {:multiple => true, :size => 5}) %>
<%= f.label :hostname %><br />
<%= f.text_field :hostname, :size => 40 %>
<%= f.submit :id => "submit"%>
<% end %>
How do I make it so each selected IP is updated with the newly created service_id?
This isn't really a nested attributes thing, nor do you need virtual attributes. You're just editing a has-many relationship.
Firstly, you probably want to be using the edit/update actions to be RESTful. Read the routing guide.
In your routes.rb:
resources :services
Then:
class ServicesController
def edit
@service = Service.find(params[:id])
@available_ips = Ip.where(:service_id => nil)
end
def update
@service = Service.find(params[:id])
if @service.update_attributes params[:service]
redirect_to @service
else
render :edit
end
end
end
You don't need the accessor in your model, the collection is an accessor:
class Service < ActiveRecord::Base
has_many :ips
end
class Ip < ActiveRecord::Base
belongs_to :service
end
Then in your views/services/edit.html.erb:
<%= form_for(@service) do |f| %>
<%= f.label :ips %>
<%= f.collection_select(:ip_ids, @available_ips + @service.ips, :id, :address, { }, {:multiple => true, :size => 5}) %>
<%= f.label :hostname %><br />
<%= f.text_field :hostname, :size => 40 %>
<%= f.submit :id => "submit" %>
<% end %>