form_for 父模型 'show' 中的 "belongs_to" 模型

form_for a "belongs_to" model in 'show' of parent model

我有一个模型 "Breads" has_many "Posts"。 我想要一个表单来在 'show' 页面上为给定的 "Bread" 创建一个新的 "Post",它创建与 'Bread' 的记录的关联,其中 'show' 页面正在显示。

我尝试了几种不同的方法,但都出现错误。我在下面显示的方法给出了 "Association cannot be used in forms not associated with an object" 错误。

/views/breads/show.html.erb:

<p>
  <strong>Bread Type:</strong>
  <%= @bread.bread_type %>
</p>

<table>
  <tr>
    <th>Uploaded By</th>
    <th>Comment</th>
    <th>Picture</th>
  </tr>
<% @bread.posts.each do |post| %>
  <tr>
    <td><%= post.uploader %></td>
    <td><%= post.comment %></td>
    <td><%= image_tag post.attachment_url.to_s %></td>
  </tr>

<% end %>
</table>

<%= @bread.id %>

<%= simple_form_for @bread do |b| %>
  <%= simple_fields_for :posts do |p| %>
    <%= p.input :uploader %>
    <%= p.input :comment %>
    <%= p.association :bread, value: @bread.id %>
    <%= p.file_field :attachment %><br>
    <%= p.button :submit %>
  <% end %>
<% end %>

<%= link_to 'Back', breads_path %>

config/routes.rb

Rails.application.routes.draw do
  get 'welcome/index'

  root 'welcome#index'

  resources :breads

  resources :posts
end

controllers/breads_controller.rb:

class BreadsController < ApplicationController
  def index
    @breads = Bread.all
  end

  def show
    @bread = Bread.find(params[:id])
  end

  def new
    @bread = Bread.new
  end

  def edit
    @bread = Bread.find(params[:id])
  end

  def create
    @bread = Bread.new(bread_params)

    if @bread.save
      redirect_to @bread
    else
      render 'new'
    end
  end

  def update
    @bread = Bread.find(params[:id])

    if @bread.update(bread_params)
      redirect_to @bread
    else
      render 'edit'
    end
  end

  def destroy
    @bread = Bread.find(params[:id])
    @bread.destroy

    redirect_to breads_path
  end

  private
    def bread_params
      params.require(:bread).permit(:bread_type)
    end
end

models/bread.rb:

class Bread < ActiveRecord::Base
  has_many :posts
  validates :bread_type,  presence: true, uniqueness: true
end

models/post.rb:

class Post < ActiveRecord::Base
  belongs_to :bread
  mount_uploader :attachment, AttachmentUploader
end

这样做 -

  <%= simple_form_for @bread do |b| %>
    <%= b.simple_fields_for(:posts,@bread.posts.build) do |p| %>
      <%= p.input :uploader %>
      <%= p.input :comment %>
      <%= p.file_field :attachment %><br>
      <%= p.button :submit %>
    <% end %>
  <% end %>

并在 beard_params

中进行更改
 def beard_params
   params.require(:bread).permit!
 end

此处 permit! 需要所有参数,对于其他方式,您可以使用@pawan 的回答。

扩展@Amit Suroliya答案,您需要将posts_attributes添加到bread_params

def bread_params
   params.require(:bread).permit(:id, :bread_type, posts_attributes: [:id, :uploader, :comment, :bread_id, :attachment])
end

更新:

您还需要在面包模型中添加accepts_nested_attributes_for :posts

对不起,但这根本不是好方法,尽量不要滥用 rails 和休息路线 :)

这里是如何做到这一点的简单示例:

config/routes.rb

resources :bread do 
  resources :posts
end

这意味着会有如下路线:

bin/rake routes

breads - breads#index
bread/:id - breads#show
etc..
and most important
bread/:bread_id/posts/:id
...

这意味着帖子是面包的嵌套资源...

app/controllers/breads_controller.rb

controller BreadsController < BaseController
   before_action :find_bread, except: %i(index create new)

   .... action new, update, edit etc..
end

但现在它是 PostsController 中的重要部分..

app/controllers/posts_controller.rb

controller PostsController < BaseController
   before_action :find_bread
   before_action :find_post, except: %i(index new create)
   before_action :build_post, only: %i(new create)

   .... action new, update, edit etc..

   # Example with :return link 
   def create
    if @post.save
       if params[:back] == 'bread_show'
         redirect_to bread_path(@bread)
       else
         redirect_to bread_post_path(@bread, @post)
       end
     else
       render 'new'
     end
   end

   private

   def build_post
      if params[:post]
         @post = @bread.posts.build(post_params)
      else
         @post = @bread.posts.build
      end
   end

   def find_post
     @post = @bread.posts.find(params[:id])
   end

   def find_bread
     @bread = Bread.find(params[:bread_id])
   end

   ... post params ...
end

现在你有完整的休息路线,你可以做你想做的事而不会那么痛苦和干净

... output hidden

<%= @bread.id %>

<%= simple_form_for @bread.posts.build do |b| %>
  <%= p.input :uploader %>
  <%= p.input :comment %>
  <%= p.file_field :attachment %><br>
  <%# Send back link to return on proper page %>
  <%= p.hidden_field :back, 'bread_show' %>
  <%= p.button :submit %>
<% end %>

<%= link_to 'Back', breads_path %>

可能会有一些错误,我凭记忆写这段代码,不能尝试:(