在Rails中,如何将RESTful操作用于多对多关系中的连接资源?

时间:2009-08-19 08:36:45

标签: ruby-on-rails rest

我有以下型号:

class User < ActiveRecord::Base
  has_many :subscriptions
end

class Subscription < ActiveRecord::Base
  belongs_to :user
  belongs_to :queue
end

class Queue < ActiveRecord::Base
  has_many :subscriptions
end

我希望在Subscription类中有一些元数据,并允许用户使用每个订阅元数据维护每个订阅的详细信息。队列会生成消息,这些消息将发送给具有“队列订阅”的用户。

我认为我想要的资源是订阅列表,即用户将填写一个包含他们可以订阅的所有队列的表单,并为每个队列设置一些元数据。如何创建RESTful Rails资源来实现此目的?我的Subscription类设计错了吗?

我现在在我的routes.rb:

中有这个
map.resources :users do |user|
  user.resources :subscriptions
end

但这会使每个订阅成为资源,而不是单个资源的订阅列表。

感谢。

2 个答案:

答案 0 :(得分:2)

使用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 setter创建和更新子记录。有关可能性的更多详细信息,请参阅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

到目前为止,这是沼泽标准,魔法发生在视图中以及如何设置参数: 应用程序/视图/订阅/ 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 %>

答案 1 :(得分:0)

我发现本教程非常有用,因为我试图通过Follows连接表将用户与用户联系起来:http://railstutorial.org/chapters/following-users