以一种形式创建深度嵌套 Rails 关联
Create Deeply Nested Rails Associations in One Form
我的欢迎页面上有一个用户表单。提交用户表单后,我想创建一个属于该用户的网站记录以及一个属于该网站的页面记录。
我正在尝试使用 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
我现在遇到的问题是用户名被保存为页面和网站名称等。我认为这是我的参数问题。另外,我不确定如何设置重定向以在创建页面后重定向到该页面。
几周来我一直在尝试各种配置,但我无法破解它。我不能强调我对我在这里做什么知之甚少,真的很想得到一些帮助!
回调 是在对象生命周期的特定时刻调用的方法。通过回调,可以编写代码,在创建、保存、更新、删除、验证或从数据库加载 Active Record 对象时 运行。
因此,当创建 user
时需要创建 website
和 page
,因此您可以使用 after_create
或 before_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
因此,一旦您的用户被创建,website
和 page
也将被创建。
要从表单中获取 page
的 content
,您可以执行以下操作:
在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
也不需要被允许,因为它会在嵌套表单的情况下自动关联。
我的欢迎页面上有一个用户表单。提交用户表单后,我想创建一个属于该用户的网站记录以及一个属于该网站的页面记录。
我正在尝试使用 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
我现在遇到的问题是用户名被保存为页面和网站名称等。我认为这是我的参数问题。另外,我不确定如何设置重定向以在创建页面后重定向到该页面。
几周来我一直在尝试各种配置,但我无法破解它。我不能强调我对我在这里做什么知之甚少,真的很想得到一些帮助!
回调 是在对象生命周期的特定时刻调用的方法。通过回调,可以编写代码,在创建、保存、更新、删除、验证或从数据库加载 Active Record 对象时 运行。
因此,当创建 user
时需要创建 website
和 page
,因此您可以使用 after_create
或 before_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
因此,一旦您的用户被创建,website
和 page
也将被创建。
要从表单中获取 page
的 content
,您可以执行以下操作:
在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
也不需要被允许,因为它会在嵌套表单的情况下自动关联。