【问题标题】:In Rails, how do I use RESTful actions for a resource that is the join in a many to many relationship?在 Rails 中,如何对作为多对多关系连接的资源使用 RESTful 操作?
【发布时间】:2010-11-20 21:02:37
【问题描述】:

我有以下型号:

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

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

谢谢。

【问题讨论】:

    标签: ruby-on-rails rest


    【解决方案1】:

    这可以很容易地使用 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 %>
    

    【讨论】:

    • 谢谢!我已经通过一些调整对您提出的建议进行了更改,并且基础工作正常。一个问题是我在订阅中获取了 0 作为 queue_id 的行。这是我取消选中复选框的时候。是否可以在未选中时删除这些行?
    • 在用户模型中尝试以下行:accepts_nested_attributes_for :subscriptions, :reject_if => proc { |attributes|属性['queue_id'].to_i.zero? }
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 2021-02-25
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多