Rails 嵌套形式 has_many :through,如何编辑连接模型的属性?

发布于 2024-08-19 22:39:44 字数 1055 浏览 11 评论 0原文

使用accepts_nested_attributes_for时如何编辑连接模型的属性?

我有 3 个模型:由链接器连接的主题和文章

class Topic < ActiveRecord::Base
  has_many :linkers
  has_many :articles, :through => :linkers, :foreign_key => :article_id
  accepts_nested_attributes_for :articles
end
class Article < ActiveRecord::Base
  has_many :linkers
  has_many :topics, :through => :linkers, :foreign_key => :topic_id
end
class Linker < ActiveRecord::Base
  #this is the join model, has extra attributes like "relevance"
  belongs_to :topic
  belongs_to :article
end

因此,当我在主题控制器的“新”操作中构建文章时...

@topic.articles.build

...并在 topic/new.html.erb... 中创建嵌套形式

<% form_for(@topic) do |topic_form| %>
  ...fields...
  <% topic_form.fields_for :articles do |article_form| %>
    ...fields...

。 ..Rails 自动创建链接器,这很棒。 现在回答我的问题:我的链接器模型还具有我希望能够通过“新主题”表单更改的属性。但是 Rails 自动创建的链接器除了 topic_id 和article_id 之外的所有属性都具有 nil 值。如何将其他链接器属性的字段放入“新主题”表单中,这样它们就不会为零?

How do you edit the attributes of a join model when using accepts_nested_attributes_for?

I have 3 models: Topics and Articles joined by Linkers

class Topic < ActiveRecord::Base
  has_many :linkers
  has_many :articles, :through => :linkers, :foreign_key => :article_id
  accepts_nested_attributes_for :articles
end
class Article < ActiveRecord::Base
  has_many :linkers
  has_many :topics, :through => :linkers, :foreign_key => :topic_id
end
class Linker < ActiveRecord::Base
  #this is the join model, has extra attributes like "relevance"
  belongs_to :topic
  belongs_to :article
end

So when I build the article in the "new" action of the topics controller...

@topic.articles.build

...and make the nested form in topics/new.html.erb...

<% form_for(@topic) do |topic_form| %>
  ...fields...
  <% topic_form.fields_for :articles do |article_form| %>
    ...fields...

...Rails automatically creates the linker, which is great.
Now for my question: My Linker model also has attributes that I want to be able to change via the "new topic" form. But the linker that Rails automatically creates has nil values for all its attributes except topic_id and article_id. How can I put fields for those other linker attributes into the "new topic" form so they don't come out nil?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷路的信 2024-08-26 22:39:44

找到了答案。技巧是:

@topic.linkers.build.build_article

构建链接器,然后为每个链接器构建文章。所以,在模型中:
topic.rb 需要 accepts_nested_attributes_for :linkers
linker.rb 需要 accepts_nested_attributes_for :article

然后采用以下形式:

<%= form_for(@topic) do |topic_form| %>
  ...fields...
  <%= topic_form.fields_for :linkers do |linker_form| %>
    ...linker fields...
    <%= linker_form.fields_for :article do |article_form| %>
      ...article fields...

Figured out the answer. The trick was:

@topic.linkers.build.build_article

That builds the linkers, then builds the article for each linker. So, in the models:
topic.rb needs accepts_nested_attributes_for :linkers
linker.rb needs accepts_nested_attributes_for :article

Then in the form:

<%= form_for(@topic) do |topic_form| %>
  ...fields...
  <%= topic_form.fields_for :linkers do |linker_form| %>
    ...linker fields...
    <%= linker_form.fields_for :article do |article_form| %>
      ...article fields...
末が日狂欢 2024-08-26 22:39:44

当 Rails 生成的表单提交给 Rails controller#action 时,params 将具有与此类似的结构(添加了一些组成的属性):

params = {
  "topic" => {
    "name"                => "Ruby on Rails' Nested Attributes",
    "linkers_attributes"  => {
      "0" => {
        "is_active"           => false,
        "article_attributes"  => {
          "title"       => "Deeply Nested Attributes",
          "description" => "How Ruby on Rails implements nested attributes."
        }
      }
    }
  }
}

注意 >linkers_attributes 实际上是一个带有 String 键的零索引 Hash,而不是 Array?嗯,这是因为发送到服务器的表单字段键如下所示:

topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]

创建记录现在非常简单:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end

When the form generated by Rails is submitted to the Rails controller#action, the params will have a structure similar to this (some made up attributes added):

params = {
  "topic" => {
    "name"                => "Ruby on Rails' Nested Attributes",
    "linkers_attributes"  => {
      "0" => {
        "is_active"           => false,
        "article_attributes"  => {
          "title"       => "Deeply Nested Attributes",
          "description" => "How Ruby on Rails implements nested attributes."
        }
      }
    }
  }
}

Notice how linkers_attributes is actually a zero-indexed Hash with String keys, and not an Array? Well, this is because the form field keys that are sent to the server look like this:

topic[name]
topic[linkers_attributes][0][is_active]
topic[linkers_attributes][0][article_attributes][title]

Creating the record is now as simple as:

TopicController < ApplicationController
  def create
    @topic = Topic.create!(params[:topic])
  end
end
§对你不离不弃 2024-08-26 22:39:44

在解决方案中使用 has_one 时的快速陷阱。
我只需将用户 KandadaBoggu 给出的答案复制粘贴到 此线程


has_onehas_many 关联的 build 方法签名不同。

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

has_many 关联的构建语法:

user.messages.build

has_one 关联的构建语法:

user.build_profile  # this will work

user.profile.build  # this will throw error

阅读 has_one 关联 文档 了解更多详细信息。

A quick GOTCHA for when using has_one in your solution.
I will just copy paste the answer given by user KandadaBoggu in this thread.


The build method signature is different for has_one and has_many associations.

class User < ActiveRecord::Base
  has_one :profile
  has_many :messages
end

The build syntax for has_many association:

user.messages.build

The build syntax for has_one association:

user.build_profile  # this will work

user.profile.build  # this will throw error

Read the has_one association documentation for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文