无缘无故创建的 Rails 活动记录对象

Rails Active Record Object being created for no reason

提问人:User12234327832 提问时间:10/26/2023 最后编辑:User12234327832 更新时间:10/28/2023 访问量:105

问:

我正在使用 Rails 7。我有模型 Post、Venue 和 VenuePost 模型。它们如下所示:

class Post < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  accepts_nested_attributes_for :venue_posts
end

class Venue < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
end

class VenuePost < ApplicationRecord
  belongs_to :post
  belongs_to :venue
end

现在,我的 Posts#new 操作如下所示:

def new
  @post = Post.new
  Venue.all.each do |v|
    vp = @post.venue_posts.build(venue: v)
    v.venue_posts << vp
  end
end

问题是,即使我不调用创建操作,帖子仍会保存到数据库中,并显示在索引页面上。为什么会这样,我怎样才能防止它,同时仍然保持我现在的相同行为,即在创建新帖子时为每个场地实例化一个 VenuePost,并能够在表单中编辑它并保存它。

感谢您的阅读

编辑以供参考:

强参数:

def post_params
  params.require(:post).permit(:title, :content, venue_posts_attributes: [:id, :title, :content])
end

嵌套形式:

<%= form.fields_for :venue_posts do |vpf| %>
  <div>
      <strong>Venue:</strong>
      <%# vpf.object.venue.name %>
      <%= vpf.label :title, style: "display: block" %>
      <%= vpf.text_field :title %>
      <%= vpf.label :content, style: "display: block" %>
      <%= vpf.text_area :content %>
  </div>
<% end %>

Post的创建方法:

def create
  @post = Post.new(post_params)

  respond_to do |format|
    if @post.save
      format.html { redirect_to post_url(@post), notice: "Post was successfully created." }
      format.json { render :show, status: :created, location: @post }
    else
      format.html { render :new, status: :unprocessable_entity }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end

目前新的发布方法:

def new
  @post = Post.new
  Venue.all.each do |v|
    @post.venue_posts.new(venue: v)
  end
end
Ruby-on-Rails Ruby ActiveRecord

评论

0赞 tadman 10/26/2023
如果你有一个,那么你可以完成它。超级简单!has_many :venues, through: :venue_posts@post.venues << v
0赞 User12234327832 10/27/2023
好的,谢谢,但这仍然适用于accepts_nested_attributes_for吗(这意味着我在创建帖子时是否能够显示所有 VenuePosts 的表单)?
0赞 tadman 10/27/2023
如果你有一些接受嵌套属性的东西,那就更容易了,你只需封装该类型记录的 Rails 参数Post.new(post_params)post_params
0赞 User12234327832 10/27/2023
好的,但是如果我想在我的表单中使用fields_for,我仍然需要一些模型参考,对吧?
0赞 tadman 10/27/2023
没错,但在某些情况下,它会为你处理好。through

答:

1赞 engineersmnky 10/26/2023 #1

我相信导致记录保存,这至少在文档中有所暗示。<<

相反,要为每个实例化一个,您应该能够进行以下调整PostVenue

class Post < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  has_many :venues, through: :venue_posts
end

class Venue < ApplicationRecord
  has_many :venue_posts, dependent: :destroy
  has_many :posts, through: :venue_posts
end

在控制器操作中

def new
  Venue.all.each {|v| v.posts.build}
end

评论

0赞 User12234327832 10/27/2023
好的,谢谢,但这仍然适用于accepts_nested_attributes_for吗(这意味着我在创建帖子时是否能够显示所有 VenuePosts 的表单)?
1赞 Alex 10/26/2023 #2

<<方法确实保存了新记录,解释有点微妙:

通过将一条或多条记录的外键设置为关联的主键,将这些记录添加到集合中。由于扁平化其参数列表并插入每条记录,因此 push 和 concat 的行为相同。返回 self,因此可以将多个追加链接在一起。<<

也许这让它更清楚一点:

post = Post.new  #=> #<Post:0x00007fdbc7279610 id: nil>
venue_post = post.venue_posts.build(venue: Venue.first)
venue_post.post  #=> #<Post:0x00007fdbc7279610 id: nil>

# when you save venue_post the new post is also saved
venue_post.save
#=>
# TRANSACTION (0.1ms)  begin transaction
# Post Create (0.4ms)  INSERT INTO "posts" DEFAULT VALUES RETURNING "id"
# VenuePost Create (0.1ms)  INSERT INTO "venue_posts" ("venue_id", "post_id") VALUES (?, ?) RETURNING "id"  [["venue_id", 1], ["post_id", 5]]
# TRANSACTION (0.1ms)  commit transaction

这就是您使用时发生的情况,但对于所有venue_posts。<<

据我所知,你根本不需要部分,因为你只是在为你的表单建立新的记录,你真的想在这里使用关联:
https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
v.venue_posts << vphas_many through:

评论

0赞 User12234327832 10/27/2023
好的,谢谢,但这仍然适用于accepts_nested_attributes_for吗(这意味着我在创建帖子时是否能够显示所有 VenuePosts 的表单)?
0赞 Alex 10/27/2023
添加关联是可选的,它只是添加快捷方式方法并为您执行连接,例如或。如果需要,您仍然可以使用与嵌套属性的关联。如果您的表单中有额外的字段用于venue_posts,您确实需要,如 .你没有在问题中包含你的表单,所以我只关注“无缘无故创建的对象”部分。through:Venue.first.postsPost.first.venueshas_many :venue_postsaccepts_nested_attributes_for :venue_postsf.fields_for :venue_posts do |ff|
0赞 User12234327832 10/27/2023
好的,部分字段是我现在已经使用的,所以这很棒!稍后会尝试,谢谢!