这可以很容易地使用 Accepts_nested_attributes_for 和 fields_for 完成:
首先在用户模型中执行以下操作:
class User < ActiveRecord::Base
has_many :subscriptions
accepts_nested_attributes_for :subscriptions, :reject_if => proc { |attributes| attributes['queue_id'].to_i.zero? }
# if you hit scaling issues, optimized the following two methods
# at the moment this code is suffering from the N+1 problem
def subscription_for(queue)
subscriptions.find_or_initialize_by_queue_id queue.id
end
def subscribed_to?(queue)
subscriptions.find_by_queue_id queue.id
end
end
这将允许您使用 subscriptions_attributes 设置器创建和更新子记录。有关可能性的更多详细信息,请参阅accepts_nested_attributes_for
现在您需要设置路由和控制器来执行以下操作:
map.resources :users do |user|
user.resource :subscriptions # notice the singular resource
end
class SubscriptionsController < ActionController::Base
def edit
@user = User.find params[:user_id]
end
def update
@user = User.find params[:user_id]
if @user.update_attributes(params[:user])
flash[:notice] = "updated subscriptions"
redirect_to account_path
else
render :action => "edit"
end
end
end
到目前为止,这是沼泽标准,神奇之处在于视图以及您如何设置参数:
app/views/subscriptions/edit.html.erb
<% form_for @user, :url => user_subscription_path(@user), :method => :put do |f| %>
<% for queue in @queues %>
<% f.fields_for "subscriptions[]", @user.subscription_for(queue) do |sf| %>
<div>
<%= sf.check_box :queue_id, :value => queue.id, :checked => @user.subscribed_to?(queue) %>
<%= queue.name %>
<%= sf.text_field :random_other_data %>
</div>
<% end %>
<% end %>
<% end %>