首页 > 解决方案 > 在表单中创建带有子对象的嵌套对象

问题描述

我是一个正在尝试在他的应用程序中做某事的 Rails 菜鸟。我的问题是:

我有一个 Corso 模型、一个 Libro 模型和一个 Annuncio 模型。Corso has_many Libro, Libro has_many Annuncio, Annuncio belongs_to Libro 和 Libro belongs_to Corso。我想要一个用户可以创建 Libro 的表单(必须与 Corso 相关联),同时必须创建该 Libro 的 Annuncio。我真的吓坏了,我看到了数百次讨论,但没有解决我的问题。每次我改变一些东西时,我都会得到一些不同的错误。

我的重点是: - 当我提交表单时,如何将 corso_id(我的意思是,对象 Corso 已经在数据库中定义)传递给新的 Libro;-我不明白为什么要创建 Libro 对象(所有字段为零),但 Annuncio 对象却没有。似乎 LibroController/new 中的代码 @libro.annuncios.build 没用。

我希望你能帮助我让这个表格正常工作。

图书馆控制器:

class LibroController < ApplicationController
  def new
    @corso = Corso.find(params[:corso_id])
    @libro = @corso.libros.build
    @libro.annuncios.build
  end

  def create
    @corso = Corso.find(params[:corso_id])
    @libro = @corso.libros.build(libro_params)
    if @libro.save
       redirect_to @libro
    else
      redirect_to root_path
    end
  end

  def show
    @libro = Libro.find(params[:id])
  end

  def index
  end



  private
    def libro_params
      params.require(:libro).permit(:titolo, :autori, :casa_editrice, :edizione, :anno_pubblicazione, :ISBN, :immagine, :corso_id, annuncios_attributes[:prezzo, :note])
  end
end

Annuncio控制器:

class AnnuncioController < ApplicationController
  def new
    @annuncio = Annuncio.new
  end

  def create
    @libro = Libro.find(params[:libro_id])
    @annuncio = @libro.annuncio.build(annuncio_params)
    if @annuncio.save
      redirect_to @libro
    else
      redirect_to root_path
    end
  end


  private
    def annuncio_params
      params.require(:annuncio).permit(:prezzo, :note)
    end
end

天秤座型号:

class Libro < ApplicationRecord
  belongs_to :corso, inverse_of: :libros
  has_many :annuncios, inverse_of: :libro

  accepts_nested_attributes_for :annuncios
end

通告型号:

class Annuncio < ApplicationRecord
  belongs_to :utente, inverse_of: :annuncios
  belongs_to :libro, optional: true, inverse_of:  :annuncios
end

科索型号:

class Corso < ApplicationRecord
  belongs_to :facolta
  has_many :libros
  validates :nome, uniqueness: true
end

routes.rb(有点乱)

Rails.application.routes.draw do

  get 'facolta/new'
  get 'sessions/create'
  get 'sessions/destroy'
  get 'users/new'
  get 'corso/index'

  get 'auth/:provider/callback', to: 'sessions#create'
  get 'auth/failure', to: redirect('/')
  get 'signout', to: 'sessions#destroy', as: 'signout'


  resources :sessions, only: [:create, :destroy]
  resource :home, only: [:show]

  root 'facolta#index'
  get 'corso_new' => 'corso#new' 
  get 'libro_new' => 'libro#new'
  get 'about_us' => 'static_pages#about_us'
  get 'faq' => 'static_pages#faq'

  resources :facolta do
    resources :corso
  end

  resources :corsos, shallow: true do
    resources :libro
  end

  resources :libros do
    resources :annuncio
  end

  resources :user do
    resources :annuncio
  end
end

意见/图书馆/新

<h1>FORM DI REGISTRAZIONE HERE</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for([@corso, @libro]) do |libro| %>
      <p>
        <%= libro.label :titolo %>
        <%= libro.text_field :titolo %>
      </p>
      <p>  
        <%= libro.label :autori %>
        <%= libro.text_field :autori %>
      </p>
      <p>
        <%= libro.label :casa_editrice %>
        <%= libro.text_field :casa_editrice %>
      </p>
      <p>
        <%= libro.label :edizione %>
        <%= libro.text_field :edizione %>
      </p>
      <p>
        <%= libro.label :anno_pubblicazione %>
        <%= libro.text_field :anno_pubblicazione %>
      </p>
      <p>
        <%= libro.label :ISBN %>
        <%= libro.text_field :ISBN %>
      </p>
      <p>
        <%= libro.label :immagine %>
        <%= libro.text_field :immagine %>
      </p>

      <%= libro.fields_for :annuncios do |annuncio| %>
        <p>
          <%= annuncio.label :prezzo %>
          <%= annuncio.text_field :prezzo %>
        </p>
        <p>
          <%= annuncio.label :note %>
          <%= annuncio.text_field :note %>
        </p>
      <% end %>

       <%= libro.hidden_field :corso_id, value: params[:post_id]%>
       <%= libro.submit "Inserisci il libro", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

架构.rb

  create_table "annuncios", force: :cascade do |t|
    t.integer "user_id"
    t.integer "libro_id"
    t.string "prezzo"
    t.text "note"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["libro_id"], name: "index_annuncios_on_libro_id"
    t.index ["user_id"], name: "index_annuncios_on_user_id"
  end

  create_table "corsos", force: :cascade do |t|
    t.string "nome"
    t.integer "facolta_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["facolta_id"], name: "index_corsos_on_facolta_id"
  end

  create_table "facolta", force: :cascade do |t|
    t.string "nome"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "libros", force: :cascade do |t|
    t.string "titolo"
    t.string "autori"
    t.string "casa_editrice"
    t.string "edizione"
    t.string "anno_pubblicazione"
    t.string "ISBN"
    t.string "immagine"
    t.integer "corso_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["corso_id"], name: "index_libros_on_corso_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "provider"
    t.string "uid"
    t.string "name"
    t.string "oauth_token"
    t.datetime "oauth_expires_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "email"
  end

编辑:使用@arieljuod 建议编辑

标签: ruby-on-railsruby-on-rails-5

解决方案


您不需要在corso_id此处合并:@libro = @corso.libros.build(libro_params.merge({corso_id: @corso.id}))。ActiveRecord 已经设置了 corso_id ,因为你正在这样做@corso.libros.build(...)

您也不需要带有 Corso id 的 hidden_​​field,因为您已经从 URL 中获得了它。

你可能也想做@libro = @corso.libros.build你的new行动。

最后,我认为这是主要问题:这是错误belongs_to :corso, inverse_of: :corsos的,应该是inverse_of: :libros

修复我指出的其他内容以清理您的代码。

编辑:

添加一个选择做这样的事情:

= libro.select :corso_id, options_from_collection_for_select(Corso.all, :id, :name)

推荐阅读