在Rails中保存动态字段

Cam*_*ron 6 ruby-on-rails

在我的Rails应用程序I Pages,Blocks,BlockContents,Fields和FieldContents中.

协会是:

class Page < ActiveRecord::Base
  has_many :blocks
  has_many :block_contents, :through => :blocks
end

class Block < ActiveRecord::Base
  belongs_to :page
  has_many :block_contents
end

class BlockContent < ActiveRecord::Base
  belongs_to :block
  has_many :field_contents
end

class Field < ActiveRecord::Base
  has_many :field_contents
end

class FieldContent < ActiveRecord::Base
  belongs_to :block_content
  belongs_to :field
  validates :content, presence: true
end
Run Code Online (Sandbox Code Playgroud)

使用这个,我可以为Page拥有动态字段.

但是,写入DB当前是在控制器中完成的,如下所示:

def update
  @page = Page.find(params[:id])
  if params[:field_content].present?
    params[:field_content].each do |block_content|
      block_content.last.each do |field|
        field_content_row = FieldContent.where(block_content_id: block_content.first, field_id: field.first).first
        if field_content_row.present?
          field_content_row.update(content: field.last)
        else
          field_content = FieldContent.new
          field_content.block_content_id = block_content.first
          field_content.field_id = field.first
          field_content.content = field.last
          field_content.save
        end
      end
    end
  end
  if @page.update_attributes(page_params)
    redirect_to pages_path
  else
    render 'edit'
  end
end
Run Code Online (Sandbox Code Playgroud)

虽然这在工作中有用,但它很脏并且它没有在视图中显示我对FieldContent的验证(验证确实有效,因为如果它们无效则不保存FieldContent,但它应该阻止整个页面保存并在视图中显示).

我怎样才能使它能够显示FieldContent的验证?


对于那些想要查看视图的人:

<% @page.blocks.each do |block| %>
    <% block.block_contents.each do |block_content| %>
        <% field_group.fields.each do |field| %>
            <input name="field_content[<%= block_content.id %>][<%= field.id %>]" id="field_content_<%= block_content.id %>_<%= field.id %>" type="text" value="<%= get_field_content(block_content, field.name) %>">
        <% end %>
    <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

和我用来获取内容的助手:

def get_field_content(block_content, field)
  content = ''
  block_content.field_contents.each do |field_content|
    if field_content.field.name == field && field_content.block_content_id == block_content.id
      content = field_content.content
    end
  end
  content
end
Run Code Online (Sandbox Code Playgroud)

Cra*_*tor 2

首先,为了提交包含多个模型的表单,您首先需要做的是接受嵌套属性。

在 page.rb 文件中,输入:

class Page < ActiveRecord::Base
has_many :blocks
has_many :block_contents, :through => :blocks
accepts_nested_attributes_for :field_contents
Run Code Online (Sandbox Code Playgroud)

其次,在视图中 - 您必须使用“fields_for”指定哪些字段适用于哪个模型,因此在 form_for @page 中,您应该放置:

 <%= f.fields_for :field_contents do |b| %>
Run Code Online (Sandbox Code Playgroud)

因为 :field_contents 是唯一会与 @page 一起更新的对象。因此整个表单元素看起来像这样:

<% @page.blocks.each do |block| %>
    <% block.block_contents.each do |block_content| %>
        <% field_group.fields.each do |field| %>
            <%= form_for @page do |f| %>
                <%= f.input :any attribute %>
                    <%= f.fields_for :field_contents do |b| %>
                        <%= b.text_field :content %>
                            <%= f.fields_for :block_contents do |b| %>
                               <%= b.hidden_field :block_content, value: "#{@block_content.id}"%>
                    <% end %>
                <% end %>
            <% end %>
        <% end %>
    <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

因为我了解到您已经可以访问 @page.field_content,所以您不必触摸控制器中的任何内容,因为它会根据现有关系自动更新记录。

现在我们已经在单个请求中提交了所有模型,您指定了希望在验证发生后在视图中显示错误消息。这是最简单的部分。

据我所知,您当前正在验证:content.

在你看来:只需放置一个HTML标签或rails内容标签

<p class= "error"><%= "Your error message"if @field_content.errors[:content].present? %></p>
Run Code Online (Sandbox Code Playgroud)

如果您还有任何疑问,请告诉我。