在窗体中创建带有子项的嵌套对象

时间:2019-05-28 21:05:27

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

我是Rails新手,正在尝试在他的应用中执行某项操作。 我的问题是:

我有一个Corso模型,一个Libro模型和一个Annuncio模型。 Corso has_many Libro,Libro has_many Annuncio,Annuncio属于Libro,而Libro属于Corso。我想要一个用户可以创建Libro(必须与Corso相关联)的表单,同时必须创建该Libro的Annuncio。我真的吓坏了,我看到了数百个讨论,但没有任何解决我的问题的方法。每次我更改某些内容时,都会遇到一些不同的错误。

我的重点是: -提交表单时如何将corso_id(我的意思是说,Corso对象已经在数据库中定义)传递给新的Libro了; -我看不到为什么创建了一个Libro对象(所有字段均为nil),但没有创建Annuncio对象。看来LibroController / new中的@ libro.annuncios.build代码是没有用的。

希望您能帮助我使此表格生效。

LibroController:

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

AnnuncioController:

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

Libro型号:

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

  accepts_nested_attributes_for :annuncios
end

Annuncio模型:

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

Corso模型:

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

views / libro / new

<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>

schema.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建议进行编辑

2 个答案:

答案 0 :(得分:0)

也许这可以帮助您。

https://stackoverflow.com/a/55476498/10895713

或者您可以那样做。

Corso模型

class Corso < ApplicationRecord
  after_create :create_libro
end

Libro模型

class Libro < ApplicationRecord
  after_create :create_annuncio
end

来源:https://guides.rubyonrails.org/active_record_callbacks.html

答案 1 :(得分:0)

您无需在此处合并corso_id@libro = @corso.libros.build(libro_params.merge({corso_id: @corso.id}))。自从您执行@corso.libros.build(...)以来,ActiveRecord已经设置了corso_id。

您也不需要带有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)