在一个表单中创建深层嵌套的Rails关联

时间:2016-12-08 04:22:23

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

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

我试图使用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

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

几个星期以来,我一直在玩各种配置,我无法解决这个问题。我无法强调我很少知道我在这里做什么,真的很喜欢一些帮助!

1 个答案:

答案 0 :(得分:1)

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

因此,在创建website时需要创建pageuser,您可以使用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也会被创建。

要从您可以执行的表单中获取content的{​​{1}}:

page模型中:

User

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

form

因此,请在此字段中附加javascript中的内容。现在在你的控制器中也允许这个属性:

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

然后最后在我们上面写的方法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 中获得website_id,因为你也是从同一个params创建的。而且form也不需要被允许,因为在嵌套表单的情况下它会自动关联。