尝试允许以 Ruby on Rails 形式创建相关对象

问题描述 投票:0回答:1

我有一个包含选择和文本字段的表单(您可以选择一个

MediaType
或创建一个):

<div>
  <%= form.label :media_type_id, style: "display: block" %>
  <%= form.collection_select :media_type_id, MediaType.all, :id, :name, :prompt => "Select a Media Type" %>
  or create one:
  <%= form.text_field :new_media_type_name %>
</div>

模型代码包含支持

new_media_type_name
的内容:

class Medium < ApplicationRecord
  has_many :authorships
  has_many :authors, through: :authorships
  belongs_to :book_genre
  belongs_to :media_type
  attr_accessor :new_media_type_name
  before_save :create_media_type_from_name

  def create_media_type_from_name
    create_media_type(:name => new_media_type_name) unless new_media_type_name.blank?
  end  
end

这一切在控制台中都可以正常工作:

irb(main):001> m = Medium.new
=>
#<Medium:0x00007f9c867307d8
...
irb(main):002> m.create_media_type(:name => "Test")
  TRANSACTION (1.1ms)  BEGIN
  MediaType Create (2.1ms)  INSERT INTO "media_types" ("name", "created_at",     "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["name", "Test"], ["created_at", "2024-09-29 01:06:50.826184"], ["updated_at", "2024-09-29 01:06:50.826184"]]   
TRANSACTION (17.3ms)  COMMIT
=>
#<MediaType:0x00007f9c86cb6270
 id: 6,
 name: "Test",
 created_at: Sun, 29 Sep 2024 01:06:50.826184000 UTC +00:00,
 updated_at: Sun, 29 Sep 2024 01:06:50.826184000 UTC +00:00>

但是从浏览器运行应用程序不会保存新的

MediaType

这是我在运行的输出中看到的内容

rails s

Started POST "/media" for 192.168.1.142 at 2024-09-28 17:34:33 -0500
Processing by MediaController#create as HTML
  Parameters: {"authenticity_token"=>"[FILTERED]", "medium"=>{"title"=>"The New Test",     "country"=>"Canada", "published_on"=>"2024-09-05", "media_type_id"=>"", "new_media_type_name"=>"Spaceship", "book_genre_id"=>"3", "summary"=>"The summary", "cover_art_path"=>"", "isbn"=>""}, "commit"=>"Create Medium"}
  TRANSACTION (0.8ms)  BEGIN
  ↳ app/controllers/media_controller.rb:26:in `create'
  BookGenre Load (1.2ms)  SELECT "book_genres".* FROM "book_genres"    WHERE "book_genres"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/media_controller.rb:26:in `create'
  TRANSACTION (0.9ms)  ROLLBACK
  ↳ app/controllers/media_controller.rb:26:in `create'
  Rendering layout layouts/application.html.erb
  Rendering media/new.html.erb within layouts/application
  MediaType Load (1.3ms)  SELECT "media_types".* FROM "media_types"
  ↳ app/views/media/_form.html.erb:35
  BookGenre Load (1.3ms)  SELECT "book_genres".* FROM "book_genres"   ORDER BY "book_genres"."name" ASC
  ↳ app/views/media/_form.html.erb:42:in `map'
  Rendered media/_form.html.erb (Duration: 48.9ms | Allocations: 8316)
  Rendered media/new.html.erb within layouts/application (Duration: 50.5ms | Allocations: 8853)
  Rendered layout layouts/application.html.erb (Duration: 85.5ms |   Allocations: 20627)
Completed 422 Unprocessable Entity in 181ms (Views: 85.5ms | ActiveRecord: 31.2ms | Allocations: 44624)

问题是,保存失败,浏览器中显示的错误始终是“媒体类型必须存在”。 我认为这意味着它无法创建

Medium
,除非附加到它的
media_type
已经存在。 但我认为这就是模型中
before_save
块的目的。

求求各位大神们,我错过了什么? 瑞安? 瑞恩·贝茨,你在吗?

更新:我发现如果我在表单中选择

media_type
同时输入
new_media_type_name
,它会创建新的
media_type
并将新的
media_type
设置为新媒体中的
media_type
参考对象。

ruby-on-rails associations
1个回答
0
投票

要在 Rails 中创建嵌套记录,您可以使用

accepts_nested_attributes
在模型中创建 setter:

class Medium < ApplicationRecord
  # ...
  belongs_to :media_type
  accepts_nested_attributes_for :media_type,
   reject_if: :all_blank?
end

要在表单中创建输入,请使用 fields_for:

<div>
  <div class="field">
    <%= form.label :media_type_id, style: "display: block" %>
    <%= form.collection_select :media_type_id, MediaType.all, :id, :name, prompt: "Select a Media Type" %>
  </div>
  <fieldset>
    <legend>Or create one</legend>
    <%= form.fields_for(:media_type) do |media_type_form| %>
      <div class="field">
        <%= media_type_form.label :name %>
        <%= media_type_form.text_input :name %>
      </div>
    <% end %>
  </fieldset>
</div>

然后,您可以通过传递哈希选项将控制器中的嵌套属性列入白名单:

def medium_attributes
  params.require(:medium)
        .permit(
          :foo,
          :bar, 
          :baz,
          media_type_attributes: [:name]
        )
end
© www.soinside.com 2019 - 2024. All rights reserved.