【问题标题】:Create Deeply Nested Rails Associations in One Form以一种形式创建深度嵌套的 Rails 关联
【发布时间】:2016-12-08 13:18:59
【问题描述】:

我的欢迎页面上有一个用户表单。随着用户表单的提交,我想创建一个属于该用户的网站记录以及一个属于该网站的页面记录。

我正在尝试使用 fields_for,但我不确定我在做什么正确或不正确。

# welcome.html.erb

<%= form_for @user do |f| %>
    <div>
        <%= f.text_field :name' %>
     </div>
     <div>
         <%= f.email_field :email %>
     </div>
     <div>
         <%= f.password_field :password %>
     </div>
     <div>
         <%= f.fields_for :website do |website_fields| %>
             <%= website_fields.text_field :name, value: 'Untitled website' %>
         <% end %>
     </div>
     <div>
         <%= f.fields_for :page do |page_fields| %>
             <%= page_fields.text_field :name, value: 'Untitled page' %>
             <%= page_fields.text_field :content, class: 'js-PageContentHiddenField', value: 'Page content' %>
         <% end %>
     </div>
     <div>
         <%= f.submit 'Create account' %>
     </div>
 <% end %>

页面控制器如下所示...

# pages_controller.rb

def welcome
    @user = User.new
    @website = @user.websites.new
    @page = @user.websites.pages.new
end

我的路线如下...

# routes.rb

resources :users do
    resources :websites do
        resources :pages
    end
end

模型看起来像这样......

# User model

has_many :websites, :dependent => :destroy
has_many :pages, through: :websites
accepts_nested_attributes_for :websites
accepts_nested_attributes_for :pages

# Website model

belongs_to :user
has_many :pages, :dependent => :destroy

# Page model

belongs_to :website

最后是我的用户控制器...

# User controller

def create
    @user = User.new(shared_params)
    @website = @user.websites.new(website_params)
    @page = @website.pages.new(page_params)

    if @user.save
        auto_login(@user)
        @redirect_to user_website_page_path
    else
        # redirect to wherever
    end
end

private

    def shared_params
        params.require(:user).permit(:email, :password, :name)
    end

    def website_params
        params.require(:user).permit(:name, :user_id)
    end

    def page_params
        params.require(:user).permit(:name, :website_id)
    end

我现在遇到的问题是用户名被保存为页面和网站名称等。我认为这是我的参数有问题。另外,我不确定如何将重定向设置为在创建页面后重定向到页面。

我已经玩了几个星期的各种配置,但我无法破解它。我不能强调我对自己在这里所做的事情知之甚少,真的很想得到一些帮助!

【问题讨论】:

  • 所以您想自动创建它,或者用户将在表单中输入这些记录的详细信息?因为如果您使用嵌套字段,则意味着用户将输入详细信息。
  • 嘿,我在修复了一些问题后刚刚更新了问题。我将 hidden_​​field 用于具有默认或生成内容的 fields_for 字段。该网站可以自动创建,但该页面包含一些用户生成的内容,我正在使用 JS 添加到该字段中。
  • 那么为什么不使用回调来创建网站和页面呢?
  • 我什至不知道什么是回调:) 你能解释一下这可能有什么帮助吗?顺便说一句,我刚刚用一些关于我的参数的额外信息更新了这个问题。

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


【解决方案1】:

回调是在对象生命周期的特定时刻被调用的方法。使用回调,可以编写在创建、保存、更新、删除、验证或从数据库加载 Active Record 对象时运行的代码。

因此,当创建user 时,您需要创建websitepage,您可以使用after_createbefore_create 回调。 after_create 在对象创建后执行,before_create 回调在对象创建前执行。

所以在你的User 模型中你可以做的是:

after_create :create_website_and_page

def create_website_and_page
  website = websites.build(name: 'Untitled Website')
  page = website.pages.build(name: 'Untitled Page', content: 'Page Content')
  website.save # This will automatically save the associated page too
end

因此,一旦您的用户被创建,websitepage 也将被创建。

要从表单中获取pagecontent,您可以执行以下操作:

User 模型中:

attr_accessor :page_content

这将在user 对象上创建一个虚拟属性,该属性在数据库中不存在。现在在你的form:

<%= f.hidden_field :page_content, class: 'js-PageContentHiddenField' %>

所以在这个字段中附加来自 javascript 的内容。现在在您的控制器中也允许此属性:

params.require(:user).permit(:email, :password, :name, :page_content)

然后最后在我们上面写的方法create_website_and_page改成这样:

page = website.pages.build(name: 'Untitled Page', content: page_content)

这应该可以满足要求。

如果您出于任何原因仍希望使用nested_form,那么您所犯的错误就是params。只需在您的创建操作顶部放置一个debugger 并检查params。因此,要允许网站和页面的参数,您必须这样做:

def user_params
  params.require(:user).permit(:email, :password, :name, website_attributes: [:name], page_attributes: [:name, :website_id, :content])
end

但是你永远不会在params 中获得website_id,因为你也是从同一个form 创建的。而且 user_id 也不需要被允许,因为它会在嵌套表单的情况下自动关联。

【讨论】:

  • 感谢帮助,非常有趣。我尝试了 after_create 回调,但我收到错误“#
  • 哦,我在构建page 时犯了一个错误,它应该是page = website.pages.build。我已经更新了我的答案。
  • 伙计,这太疯狂了,你帮我省了几个星期拔头发的时间,非常感谢。最后一件事,是否可以以某种方式注入页面内容?我需要从 div 中的用户生成内容中获取页面内容。
  • 更新了答案。试试看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多