RESTful способ добавить сущность к другой (отношение n: m) в Rails 3? - PullRequest
2 голосов
/ 15 июня 2011

это может быть очень простая проблема, с простым решением, но я еще не понял.

Предположим, у меня есть две следующие модели:

class Task
   has_and_belongs_to_many :users
end

class User
   has_and_belongs_to_many :tasks
end

Предположим, что есть пользователь с именем "wayne" с id = 1 и задача с именем "ходить по магазинам" с id = 2. Каким будет RESTful способ создать отношения между ними через интерфейс REST?

Добавление маршрута типа users / 1 / add_task / 2 более RPC-стиль и не очень RESTful. Так как бы вы это сделали?

Ответы [ 3 ]

2 голосов
/ 21 августа 2012

Успешным способом было бы добавить модель, которая служит соединением.Затем объединяемая таблица получит свой собственный ресурс.Модель соединения может называться, например, «Подписка», или, если вы не найдете подходящего имени, просто назовите его TaskUser.Эта часть направляющих рельсов имеет отношение: http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

class Task
  has_many :users, :through => "TaskUser"
end

class User
  has_many :tasks, :through => "TaskUser"
end

class TaskUser
  has_many :users
  has_many :tasks
end

При отправке POST to /taskusers с user_id и task_id после того, как вы объявили маршрут (например, добавив resource TaskUser вroute.rb), вы создаете связь между двумя объектами.Контроллер должен включать что-то вроде этого:

class TaskUsersController
  def create
    TaskUser.create(:task_id => params[:task_id], :user_id => params[:user_id])
  end
end

, после чего вы сможете получить доступ к задачам пользователя, просто позвонив

user.tasks

Лично я думаю, что есть ситуации, когда вы ненужно это решение, так как оно создает немало накладных расходов с дополнительной моделью и всем этим.

Например, у меня есть модель предмета и я хочу добавить к ней теги.Это ассоциация «многие ко многим», объявленная has_and_belongs_to_many в каждой модели, но я всегда добавляю тег к элементу, а не наоборот, поэтому первое решение кажется немного большим.Затем я просто добавляю

put "/Items/#{item_id}/tags/#{tag_id}" => "items#add_tag"

в router.rb.ItemController:

class ItemController
  def add_tag
    item = Item.find_by_id(:item_id)
    tag = Tag.find_by_id(:tag_id)
    item.tags << tag
    item.save
  end
end

Надеюсь, это поможет в любом случае, даже если я только что увидел, что ответ опоздал на год.

2 голосов
/ 15 июня 2011

Вы можете перейти с

users / {userid} / tasks /

, где PUT в этом месте добавляет задачу с {taskid} в набор;вы также можете (одновременно) иметь

tasks / {taskid} / users /

, где PUT для этого местоположения добавляет пользователя с {userid} в набор.

0 голосов
/ 16 июня 2011

Что вы думаете об этом решении?

РЕДАКТИРОВАТЬ: Замените пользователя на AssignmentSheet и Task с Assignment для этого примера, чтобы соответствовать исходному вопросу.

Некоторые маршруты:

# routes.rb
put "assignment_usage/assignment_sheet/:assignment_sheet_id/assignment/:assignment_id" => "assignment_usage#create"
  delete "assignment_usage/assignment_sheet/:assignment_sheet_id/assignment/:assignment_id" => "assignment_usage#destroy"

И код контроллера:

# app/controllers/assignment_usage_controller.rb
class AssignmentUsageController < ApplicationController
  before_filter :load_instances

  # PUT /assignment_usage/assignment_sheet/:assignment_sheet_id/assignment/:assignment_id
  def create
    @assignment.assignment_sheets << @assignment_sheet
    redirect_to(@assignment_sheet, :notice => "Assignment has been successfully added.")
  end

  # DELETE /assignment_usage/assignment_sheet/:assignment_sheet_id/assignment/:assignment_id
  def destroy
    @assignment.assignment_sheets.delete @assignment_sheet
    redirect_to(@assignment_sheet, :notice => "Assignment has been successfully removed.")
  end

  private
  def load_instances
    @assignment_sheet = AssignmentSheet.find(params[:assignment_sheet_id])
    @assignment       = Assignment.find(params[:assignment_id])
  end
end

Возможно, для этого немного яснее использовать отдельный ресурс.

...