【问题标题】:Bidirectional many-to-many association with Rails : how to create from both ways?与 Rails 的双向多对多关联:如何从两种方式创建?
【发布时间】:2021-01-26 07:14:12
【问题描述】:

我有一个关于 Ruby on Rails 中的多对多关联的问题。

我的应用中有 3 个模型:Topic、Meeting 和 Todo 与 manu-to-many 关联。

class Todo < ApplicationRecord
  belongs_to :topic
  belongs_to :meeting
end

然后

class Meeting < ApplicationRecord
  has_many :todos
end

class Topic < ApplicationRecord
  has_many :todos
end

我让我的路由和控制器能够通过会议创建新的待办事项:

Rails.application.routes.draw do
  resources :meetings, only: [:index, :show, :new, :create, :edit, :update]  do
    resources :todos, only: [:index, :new, :create]
  end
  resources :todos, only: [:index, :show, :edit, :update, :destroy]
end

class TodosController < ApplicationController

  def new
    @topic = Topic.find(params[:topic_id])
    @todo = Todo.new
  end

  def create
    @todo = Todo.new(todo_params)
    @meeting = Meeting.find(params[:meeting_id])
    @todo.meeting = @meeting
    @todo.save
    redirect_to meeting_path(@meeting)
  end

  private
  def todo_params
    params.require(:todo).permit(:topic_id, :meeting_id, :note, :deadline, :title)
  end
end

我的看法:

<h3><%= @meeting.date %></h3>
<%= simple_form_for [@meeting, @todo] do |f| %>
  <%= f.input :title %>
  <%= f.input :note %>
  <%= f.date_field :deadline %>
  <%= f.association :topic, label_method: :nom, value_method: :id %>
  <%= f.submit "Add a todo" %>
<% end %>

我的问题是我希望能够通过主题以及添加路线时创建待办事项:

  resources :topics, only: [:index, :show, :new, :create] do
    resources :todos, only: [:index, :new, :create]
  end

当我尝试完成我的控制器并对其进行测试时,这似乎很棘手。如果我添加:

@topic = Topic.find(params[:topic_id])

然后它告诉我它需要开会……

有什么想法吗?

【问题讨论】:

    标签: ruby-on-rails many-to-many bidirectional


    【解决方案1】:

    您可以使用以下方法创建不同的路线:

    resources :meetings do
      resources :todos, only: [:index, :new, :create]
    end
    
    resources :topics do
      resources :todos, only: [:index, :new, :create]
    end
    

    您可以通过使用路由问题来避免重复:

    concerns :todoable do
      resources :todos, only: [:index, :new, :create]
    end
    
    resources :topics, concerns: :todoable
    resources :meetings, concerns: :todoable
    

    在您的控制器中,您可以检查是否存在 meeting_idtopic_id 参数:

    class TodosController < ApplicationController
      before_action :set_parent
    
      def new
        @todo = Todo.new
      end
    
      def create
        @todo = @parent.todos.new(todo_params)
        if @todo.save
          redirect_to @parent
        else
          render :new
        end
      end
    
      private
    
      def parent_class
        @parent_class ||= if params[:meeting_id].present?
          Meeting
        else if params[:topic_id].present?
          Topic
        else
          # raise an error?
        end
      end
    
      def set_parent
        id = params["#{parent_class.model_name.param_key}_id"]
        @parent = parent_class.find(id)
      end
    
      def todo_params
        params.require(:todo)
              .permit(:topic_id, :meeting_id, :note, :deadline, :title)
      end
    end
    
    <%= simple_form_for [@parent, @todo] do |f| %>
      <%= f.input :title %>
      <%= f.input :note %>
      <%= f.date_field :deadline %>
      <%= f.association :topic, label_method: :nom, value_method: :id if @parent.is_a?(Meeting) %>
      <%= f.association :meeting, label_method: :nom, value_method: :id if @parent.is_a?(Topic) %>
      <%= f.submit "Add a todo" %>
    <% end %>
    

    【讨论】:

    • 完美运行!我只在我的 TodoController 中调整了 redirect_to 来访问主题或会议。非常感谢!
    • 啊,应该是redirect_to @parent
    猜你喜欢
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    相关资源
    最近更新 更多